Python模块¶
约 2458 个字 123 行代码 预计阅读时间 10 分钟
模块¶
在退出Python的命令行解释器后,再次进入时,之前在 Python 解释器中定义的函数和变量就丢失了。因此,编写较长程序时,最好用文本编辑器代替解释器,执行文件中的输入内容,这就是编写脚本。随着程序越来越长,为了方便维护,最好把脚本拆分成多个文件。编写脚本还一个好处,不同程序调用同一个函数时,不用把函数定义复制到各个程序
为实现这些需求,Python 把各种定义存入一个文件,在脚本或解释器的交互式实例中使用。这个文件就是模块,也就是说每一个.py
文件就属于一个模块,所以引入模块就相当于引入.py
文件,在Python文件中,引入.py
文件可以使用import
关键字
例如下面的代码:
Python | |
---|---|
1 |
|
注意,当在函数内部使用import
导入模块或者定义新的函数时,这些新引入的名字(导入的模块名、函数名等)默认情况下也是在局部作用域中定义的。这意味着它们仅在当前函数内可见
Python | |
---|---|
1 2 3 4 |
|
模块包含可执行语句及函数定义。这些语句用于初始化模块,且仅在import
语句第一次遇到模块名时执行,也就是说,如果一个模块被导入,那么这个模块中所有的代码在当前文件执行时遇到import
关键字都会被执行一遍,例如下面的代码:
Python | |
---|---|
1 2 3 4 5 |
|
在上面的代码中,在test1.py
文件下运行,就可以看到尽管test1.py
文件没有任何内容,但是因为test_module.py
文件有一句打印语句,所以最后的输出结果应该是:
Python | |
---|---|
1 |
|
如果需要为引入的模块取别名,可以使用as
关键字,有了别名之后,在当前文件就只需要使用别名访问对应模块中的内容即可,例如下面的代码:
Python | |
---|---|
1 2 |
|
在Python中,每个模块都有自己的私有命名空间,它会被用作模块中定义的所有函数的全局命名空间。因此,模块作者可以在模块内使用全局变量而不必担心与用户的全局变量发生意外冲突,例如下面的代码:
Python | |
---|---|
1 2 3 4 5 6 7 8 |
|
在一个文件中如果想访问已经导入的文件中的内容时,可以使用模块名.模块内容
的方式引入已经导入的文件中的内容,例如上面代码中的test_module.a
就是访问test_module
中的变量a
如果模块中有多个内容,但是又只想在当前文件中引入指定的内容,就可以使用from...import...
语句,from
后面跟着模块名或者包名: 1. 如果from
后面跟着模块名,则import
后面跟着就是模块中具体内容的名称(不需要指定模块名)。使用这种方式引入的内容在使用时不再需要指定包名,所以如果当前文件有重名内容会产生覆盖 2. 如果from
后面跟着包名,则import
后面跟着就是具体的模块名,这个过程也被称为引包(关于包后面会讲解,现在先提出这个步骤)
Note
如果使用第一种方式引入模块中的内容,则import
关键字后面可以加上*
表示引入指定模块中的所有不以下划线_
开头的名称,但是不要用这个功能,这种方式向解释器导入了一批未知的名称,可能会覆盖已经定义的名称,并且这项操作经常让代码变得难以理解
例如下面的代码:
Python | |
---|---|
1 2 3 4 5 6 |
|
如果需要为导入的内容取别名,则可以在对应的内容后面使用as
为其取别名,例如下面的代码:
Python | |
---|---|
1 2 3 4 5 6 |
|
主函数¶
Note
本部分可以参考官方文档:以脚本方式执行模块
在Python中,主函数(通常称为 main
函数)并不是一个内置的概念,不像C或C++那样有一个明确的 main
函数作为程序的入口点。然而,Python程序员通常会定义一个名为 main
的函数来组织和执行主要的逻辑代码,并使用 if __name__ == "__main__":
语句来确保该函数只在脚本直接运行时被调用(相当于PyCharm右键直接运行)
主函数通常是一个普通函数,名称可以是 main
或其他任何名称。这个函数包含了程序的主要逻辑
Python | |
---|---|
1 2 3 |
|
为了确保 main
函数只在脚本直接运行时被调用,而不是在模块被导入时被调用,可以使用 if __name__ == "__main__":
语句。
Python | |
---|---|
1 2 3 4 5 6 |
|
使用这种方式的优点:
- 模块重用:当你的脚本作为一个模块被导入到其他脚本中时,
if __name__ == "__main__":
语句下的代码不会被执行。这样可以避免不必要的代码执行 - 测试和示例:你可以在
if __name__ == "__main__":
语句下编写一些测试代码或示例代码,这些代码只有在直接运行脚本时才会执行 - 清晰性:将主要逻辑封装在一个
main
函数中,并通过if __name__ == "__main__":
调用它,可以使代码结构更清晰,便于维护
以下是一个完整的示例,展示了如何定义和使用 main
函数:
Python | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 |
|
当直接运行这个脚本(在PyCharm中直接右键当前文件)时,输出将是:
Python | |
---|---|
1 2 3 4 |
|
如果将这个脚本保存为 my_script.py
并从另一个脚本中导入它,例如:
Python | |
---|---|
1 2 3 4 |
|
当运行 another_script.py
时,输出将是:
Python | |
---|---|
1 |
|
注意,main
函数中的代码没有被执行,因为 my_script
是作为一个模块被导入的,而不是直接运行的
列出导入模块的内容¶
在Python中,如果在一个文件中引入了一个模块,则可以在该文件中使用dir(导入的模块名)
函数查看指定模块的内容,返回结果是经过排序的字符串列表,例如下面的代码:
Note
如果dir()
函数不传递实参,则默认查看到的是当前文件中的内容
Python | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 |
|
注意dir()
函数不会列出内置函数和变量的名称。这些内容的定义在标准模块builtins
中
包¶
在Python中,所谓包就是有着__init__.py
文件的文件夹,而这个__init__.py
文件可以为空也可以设置__all__
变量,这个文件夹下的所有.py
文件就是隶属于当前包的模块
在Python中,可以使用from...import...
导入包和指定模块,例如下面的代码:
Python | |
---|---|
1 2 |
|
如果需要使用模块中的内容,有下面几种方式(注意使用其中内容的方式不同):
-
导入指定模块,通过模块调用
Python 1 2 3 4
from pack import test_module # 1. 导入指定模块,通过模块调用 print(test_module.c) # 100
-
导入包和模块,引入指定内容
Python 1 2 3
from pack.test_module import c # 2. 导入指定包中的模块,通过包名.模块名调用 print(c) # 100
-
直接引入单个模块
Python 1 2 3
import pack.test_module # 3. 直接引入单个模块 print(pack.test_module.c) # 100
Note
使用
import item.subitem.subsubitem
句法时,除最后一项外,每个item
都必须是包。最后一项可以是模块或包,但不能是上一项中定义的类、函数或变量
注意,前面在模块中提到如果使用import
关键字后面跟着的是*
就会导入该模块中所有的内容,但是在包这里就不建议这么做,因为包中可能还有大量的模块,直接使用*
可能会导致花费很长的时间,并且可能会产生不想要的副作用,如果这种副作用被设计为只有在导入某个特定的子模块时才应该发生
解决上面这个问题的办法就是提供包的显示索引,在__init__.py
文件中为变量__all__
赋值为一个列表,列表中的元素就是指定的模块名,此时使用import *
时就会导入__all__
列表中指定的模块
例如下面的代码:
Python | |
---|---|
1 2 3 4 5 6 7 8 9 |
|
需要注意,如果在__init__.py
文件中有与某个模块名重名的内容,那么此时再__all__
列表中写的模块名就会指向对应的函数而不是模块,例如下面的代码:
Python | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
在上面的代码中,并没有执行到add.py
文件中的print("导入时就执行")
,说明add.py
并没有被导入到test1.py
文件,原因就是__init__.py
文件中的add
函数覆盖了__all__
列表中的add
模块
包的相对导入¶
如果包中还有许多子包,则可以考虑使用相对导入的方式
假设当前包的结构如下:
Text Only | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
则可以在surround.py
文件中按照下面的方式导入指定的包:
Python | |
---|---|
1 2 3 |
|
注意,相对导入基于当前模块名。因为主模块名永远是__main__
,所以如果计划将一个模块用作Python应用程序的主模块,那么该模块内的导入语句必须始终使用绝对导入
假设当前项目结构如下:
Text Only | |
---|---|
1 2 3 4 |
|
在 module_a.py
中,有以下相对导入:
Python | |
---|---|
1 2 3 4 5 |
|
如果直接运行 module_a.py
:
Bash | |
---|---|
1 |
|
会出现错误:
Text Only | |
---|---|
1 |
|
这是因为当直接运行 module_a.py
时,其 __name__
等于 '__main__'
,相对导入无法解析
解决方法:使用绝对导入
修改 module_a.py
:
Python | |
---|---|
1 2 3 4 5 |
|
这样,无论模块是被导入还是直接运行,绝对导入都能正常工作