Module模块
为什么使用模块
- 模块是一种组织代码的形式,它用文件的形式,将函数、变量组织起来。
- 大大提高了代码的可维护性
- 编写代码不必从零开始
模块的两个方向
- 用于执行
- 用于被调用(没有执行效果)
调用模块的方式
- import module1
import module2 - import module1, module2
以上更推荐第一种,代码可读性更强。
另外在调用时,也可以给模块重新命名:import module as module_name
当我们在当前脚本import module时,解释器会自动把当前脚本所在的目录加入到sys.path的第一个位置,然后在sys.path的所有路径中搜寻模块。
import的两个过程
- 创建一个新的名称空间,用于存放模块中的名称和绑定对象的关系。
- 执行被调用的模块
注意:
1. 对一个模块,第二次重复导入时,不会再创建名称空间,因为已经存在了。因此,也不会有执行效果。
2. 导入模块的名称空间独立于当前脚本的名称空间,当前空间的变量和模块空间的变量即使重名,也互不影响。比如存在module.x = 10, 当前空间中也有一个全局变量x, 那无论怎样修改x的值,module.x的值都不会变。
3. 我们也可以通过from module import func1,func2/var/*
这种方式来导入模块的具体内容,这样,在调用模块中的方法时就不用通过module.func()
, 而可以直接func()
但是这样有一个问题,重名的问题。看下面这个栗子:
x = 'from test'
from module import * # 从module中导入所有对象。moduele中有一个全局变量 x = 'from module
print(x) # 这时,打印出来的结果是 "from module"
from module import * # 从module中导入所有对象。moduele中有一个全局变量 x = 'from module
x = 'from test'
print(x) # 这时,打印出来的结果是 "from test"
从上面可以看出,哪个对象生效取决于调用顺序,就近原则。
因此,在导入模块时,推荐用import的方式。
if __name__ == ‘__main__’
当我们在当前脚本print(__name__)
时,结果永远是__main__
, 而当这个脚本被调用时,__name__
的值就是被调用脚本的脚本名(模块名)。所以,在脚本中的主函数执行前,加if __name__ == '__main__'
条件判断,有一个好处,我们可以直接执行这个函数,而当这个脚本(模块)被调用时,由于if条件不成立,函数就不会执行。
Package包
包的定义
包是组织模块的方式。在python中,包可以理解为一个文件夹,但是每个文件夹里必须有一个__init__.py
文件
调用方式
from package import module
同导入模块一样,package也必须在sys.path的路径列表中才行。
注意:当我们在脚本test.py中从一个包里导入一个自定义模块A,而该模块中又导入了另一个自定义模块B时,会报错。这是因为当前的sys.path路径中找不到模块B。解决方案是,在模块A中导入模块B时,用from package import module的形式。(这个package应该与test.py在一个目录层级下)
组织程序
可以按照包来组织,一个包只放主程序,而相关调用模块则放在其它同级的包里,效果如下:
说明:bin包里面只放启动文件 bin.py;core包里面放要调用的核心模块,main模块中写函数的主逻辑。
__init__.py
调用包时:执行__init__.py
通过init 导入下面层级的包,模块。提供给外部接口时,就可以直接import最上层的包名,点方法调用各个功能,而不用通过from pack1.pack2 这样层层找的方式。
模块调用的可迁移性
我们在自己终端写的程序,调用自定义模块时路径没有问题,那如何保证程序传播给另一个终端,仍然实现模块的正常调用呢。
import sys
import os
c_path = os.path.abspath(__file__) # 获取当前脚本的绝对路径 (__file__的值时当前脚本的相对路径)
dir = os.path.basename(c_path) # 获取当前脚本的包目录
base_dir = os.path.basename(dir) # 获取包目录的上层目录base_dir(所有的包都组织在base_dir下)
sys.path.insert(0,base_dir) # 将base_dir加入sys.path, 这样在导入包下面的模块时,就都能找到了。
简化:
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0,BASE_DIR)