>>> from env_helper import info; info()
页面更新时间: 2023-12-27 09:24:07
运行环境:
Linux发行版本: Debian GNU/Linux 12 (bookworm)
操作系统内核: Linux-6.1.0-16-amd64-x86_64-with-glibc2.36
Python版本: 3.11.2
2.9. 构建合理的包层次来管理module¶
我们知道,本质上每一个Python文件都是一个模块,使用模块可以增强代码的可维护性和可重用性。但显然在大的项目中将所有的Python文件放在一个目录下并不是一个值得推荐的做法,我们需要合理地组织项目的层次来管理模块,这就是包(Package)发挥功效的地方了。
什么是包呢?简单说包即是目录,但与普通目录不同,它除了包含常规的Python文件
(也就是模块)以外,还包含一个 __init__.py
文件,同时它允许嵌套。包结构如下:
- Package/ _init_-py
Modulel.py Module2.py Subpackage/ —init_.py
Module1.py Module2.py
包中的模块可以通过访问符进行访问,即“包名.模块名”。如上述嵌套结构中访 问 Package 目录下的 Module1 可以使用 Package.Module1,而访问 Subpackage 中的 Module1 则可以使用Package.Subpackage.Module1。包中的模块同样可以被导人其他模块中。有以下几种导人方法:
1)直接导人一个包,具体如下:
import Package
2)导人子模块或子包,包嵌套的情况下可以进行嵌套导入,具体如下:
from Package import Module1 import Package.Module1 from Package import Subpackage import Package.Subpackage from Package.Subpackage import Module1 import Package,SubpackagerModule1
前面提到在包对应的目录下包含有__init__.py
文件,那么这个文件的作用是什么呢?
它最明显的作用就是使包和普通目录区分;其次可以在该文件中申明模块级别的import
语句
从而使其变成包级别可见。上例所示的结构中,如果要import
包Package
下Module1
中的类
Test
,当__init__.py
文件为空的时候需要使用完整的路径来申明import
语句:
from Package.Module1 import Test
但如果在__init__.py
文件中添加from Module1 import Test
语句,则可以直接使用from Package import Test
来导入类Test
。需要注意的是,如果__init__.py
文件为空,当意图使用
from Package import *
将包Package中所有的模块导人当前名字空间时并不能使得导人的模块
生效,这是因为不同平台间的文件的命名规则不同,Python解释器并不能正确判定模块在对
应的平台该如何导人,因此它仅仅执行__init__.py
文件,如果要控制模块的导人,则需要对
__init__.py
文件做修改。
__init__.py
文件还有一个作用就是通过在该文件中定义__all__
变量,控制需要导人的
子包或者模块s在上例的Package目录下的__init__.py
文件中添加:
__all__ =[ 'Module1', 'Module2','Subpackage']
之后再运行from Package import *
,可以看到__all__
变景中定义的模块和包被导入当前名字空间。
from Package import * dir()
包的使用能够带來以下便利:
合理组织代码,便于维护和使用。 通过将关系密切的模块组织成一个包,使项目结构更为完善和合理,从而增强代码的可维护性和实用性。以下是一个可供参考的Python 项目结构:
ProjectName/ | ——README
LICENSEsetup.pyrequirements.txtI sample/ | | __init__.py I | core.py | | helpers.py |------docs/
conf.py ifidex.rst
bin/ package/
__init__.py
subpackage/
I tests/ | | test_basic.py | | test_advanced.py
能够有效地避免名称空间冲突。 使用
from Package import Module2
可以将Module2导 人当前局部名字空间,访问的时候不冉霱要加入包名。看下面这个例子:
from Package import Module2 Modulse2.Hi()
上述代码中Subpackage中也包含Module2,当使用from… import.,.导入的时候,生效的 是 Subpackage 的 Module2。结果如下:
from Package. Subpackage import Module2 Module2.Hi ()
如果模块包含的属性和方法存在同名冲突,使用import module可以有效地避免名称冲 突。在嵌套的包结构中,每一个模块都以其所在的完整路径作为其前缀,因此,即使名称一 样,但由于模块所对应的其前缀不同,因此不会产生冲突。
import Package.Module2 Package.Modules.Hi()
import Package.Subpackage.Module2 Package.Subpackage.Module2
注意:本节所说的包与后文中谈到的软件包不同,这里的包的概念仅限于包含一个或一 系列Python文件(模块)的文件夹(目录),它的作用是合理组织代码,便于维护和使用,并 避免命名冲突。