- Preface 前言
- 第1章 引论
- 第2章 编程惯用法
- 第3章 基础语法
- 建议19:有节制地使用 from…import 语句
- 建议20:优先使用 absolute import 来导入模块
- 建议21:i+=1 不等于 ++i
- 建议22:使用 with 自动关闭资源
- 建议23:使用 else 子句简化循环(异常处理)
- 建议24:遵循异常处理的几点基本原则
- 建议25:避免 finally 中可能发生的陷阱
- 建议26:深入理解 None 正确判断对象是否为空
- 建议27:连接字符串应优先使用 join 而不是 +
- 建议28:格式化字符串时尽量使用 .format 方式而不是 %
- 建议29:区别对待可变对象和不可变对象
- 建议30:[]、() 和 {}:一致的容器初始化形式
- 建议31:记住函数传参既不是传值也不是传引用
- 建议32:警惕默认参数潜在的问题
- 建议33:慎用变长参数
- 建议34:深入理解 str() 和 repr() 的区别
- 建议35:分清 staticmethod 和 classmethod 的适用场景
- 第4章 库
- 建议36:掌握字符串的基本用法
- 建议37:按需选择 sort() 或者 sorted()
- 建议38:使用 copy 模块深拷贝对象
- 建议39:使用 Counter 进行计数统计
- 建议40:深入掌握 ConfigParser
- 建议41:使用 argparse 处理命令行参数
- 建议42:使用 pandas 处理大型 CSV 文件
- 建议43:一般情况使用 ElementTree 解析 XML
- 建议44:理解模块 pickle 优劣
- 建议45:序列化的另一个不错的选择 JSON
- 建议46:使用 traceback 获取栈信息
- 建议47:使用 logging 记录日志信息
- 建议48:使用 threading 模块编写多线程程序
- 建议49:使用 Queue 使多线程编程更安全
- 第5章 设计模式
- 第6章 内部机制
- 建议54:理解 built-in objects
- 建议55:init() 不是构造方法
- 建议56:理解名字查找机制
- 建议57:为什么需要 self 参数
- 建议58:理解 MRO 与多继承
- 建议59:理解描述符机制
- 建议60:区别 getattr() 和 getattribute() 方法
- 建议61:使用更为安全的 property
- 建议62:掌握 metaclass
- 建议63:熟悉 Python 对象协议
- 建议64:利用操作符重载实现中缀语法
- 建议65:熟悉 Python 的迭代器协议
- 建议66:熟悉 Python 的生成器
- 建议67:基于生成器的协程及 greenlet
- 建议68:理解 GIL 的局限性
- 建议69:对象的管理与垃圾回收
- 第7章 使用工具辅助项目开发
- 第8章 性能剖析与优化
建议18:构建合理的包层次来管理 module
我们知道,本质上每一个Python文件都是一个模块,使用模块可以增强代码的可维护性和可重用性。但显然在大的项目中将所有的Python文件放在一个目录下并不是一个值得推荐的做法,我们需要合理地组织项目的层次来管理模块,这就是包(Package)发挥功效的地方了。
什么是包呢?简单说包即是目录,但与普通目录不同,它除了包含常规的Python文件(也就是模块)以外,还包含一个__init__.py文件,同时它允许嵌套。包结构如下:
Package/ __init__.py Module1.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.Subpackage.Module1
前面提到在包对应的目录下包含有__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__变量,控制需要导入的子包或者模块。在上例的Package目录下的__init__.py文件中添加:
__all__ = ['Module1', 'Module2','Subpackage']
之后再运行from Package import *,可以看到__all__ 变量中定义的模块和包被导入当前名字空间。
>>> from Package import * >>> dir() ['Module1', 'Module2', 'Subpackage', '__builtins__', '__doc__', '__name__', '__package__']
包的使用能够带来以下便利:
合理组织代码,便于维护和使用。通过将关系密切的模块组织成一个包,使项目结构更为完善和合理,从而增强代码的可维护性和实用性。以下是一个可供参考的Python项目结构:
ProjectName/ |---README |----LICENSE |----setup.py |-----requirements.txt |------sample/ | |----__init__.py | |----core.py | |----helpers.py |------docs/ | |------conf.py | |------index.rst |------bin/ |------package/ | |-----__init__.py | |-----subpackage/ | |------........ |------tests/ | |------test_basic.py | |------test_advanced.py
能够有效地避免名称空间冲突。使用from Package import Module2 可以将Module2导入当前局部名字空间,访问的时候不再需要加入包名。看下面这个例子:
>>> from Package import Module2 >>> Module2.Hi() Hi from Package Module1
上述代码中Subpackage中也包含Module2,当使用from... import...导入的时候,生效的是Subpackage的Module2。结果如下:
>>> from Package.Subpackage import Module2 >>> Module2.Hi() Hi from Subpackage Module2
如果模块包含的属性和方法存在同名冲突,使用import module可以有效地避免名称冲突。在嵌套的包结构中,每一个模块都以其所在的完整路径作为其前缀,因此,即使名称一样,但由于模块所对应的其前缀不同,因此不会产生冲突。
>>> import Package.Module2 >>> Package.Module2.Hi() Hi from Package Module1 >>> import Package.Subpackage.Module2 >>> Package.Subpackage.Module2.Hi() Hi from Subpackage Module2
注意:本节所说的包与后文中谈到的软件包不同,这里的包的概念仅限于包含一个或一系列Python文件(模块)的文件夹(目录),它的作用是合理组织代码,便于维护和使用,并避免命名冲突。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论