Python 包和模块使用注意事项
- 1、 包和模块的定义
- 2、 解决变量命名冲突
- 3、 `__init__.py` 作用
- 4、 解决找不到模块的问题
Python9️⃣:0小白基础之——Python十大数据结构Python8️⃣:0小白基础之——Python 面向对象编程(下篇)Python7️⃣:0小白基础之——Python 面向对象编程(上篇)Python6️⃣:0小白基础之——Python函数专题Python5️⃣:0小白基础之——Python编程习惯专题Python4️⃣:0小白基础之——流程控制专题Python3️⃣:0小白基础之——列表专题Python2️⃣:0小白基础之——字符串专题Python1️⃣:0小白基础之——数字专题
今天这个专题讨论Python代码工程化、结构化的方法。我们都会遇到这种情景:所有代码都堆积到一个模块里,导致代码越来越长,最后变得难以维护,很明显代码只写到一个py模块文件是不可取的。如何按照逻辑功能,将代码划分到不同模块,组织为一个更易读、更易维护的代码结构呢?
.
1、 包和模块的定义
包(package)是一个文件夹,它里面会有一个 init.py ,还有我们自己定义的.py文件。
而我们自己定义的.py文件,python中称为模块(module),一个模块就是一个py文件,里面封装了一个功能模块,可能有函数、类、变量等。
如下建立的一个代码结构:
classdemo/
├── animals
│ ├── animal2.py
│ ├── animal.py
│ ├── __init__.py
│ ├── manager2.py
│ └── manager.py
└── search
├── binarytree_level.py
└── __init__.py
里面包括两个package,一个为animals包,另一个为search包. 每个package里都有一个 __init__.py
文件。
使用这种结构带来什么便利?每个模块间的变量又该如何引用?里面的 __init__.py
起到什么作用?下面一一解答。
.
2、 解决变量命名冲突
对程序员而言,变量命名往往是一个很头疼的难题,并且一不小心就会写出名称相同的变量,尤其是在同一模块里变量名称重复会很麻烦。
通常来说,一个模块里定义的代码行数不要太多,尽量拆分到不同的模块里,不同的模块允许出现相同名称的变量,这是划分不同模块的作用之一。
但是仅有模块好像还不够,对于一个大点的框架,再按照大的功能逻辑划分出包(package)显得更有必要。
并且有了package后,相同变量名字冲突的可能性会更小。如第1小节中的 Animal 类,它的完整名称实际为: animals.animal2.Animal ,这样在使用Animal等类时,导入方法是下面这样:from animals.animal2 import (Animal2,Cat,Bird)
,实际上,这种层级的组织在一些大的框架中到处可见。
.
3、 __init__.py
作用
如上所述, init.py 会使得普通的文件夹变为package. 实际上, __init__.py
也是一个模块,其名称正是package的名字。
一般来说此文件为空,如下导入 animals 包:
In []: import animals
In []: animals
Out[]: <module 'animals' from '/home/zglg/mywork/mdfiles/classdemo/animals/__init__.py'
可以看到导入 animals 包实际上导入了它下面的 init.py 文件。同时还可以为它增加其他功能。
因为在导入一个包时实际上导入它的 init.py 文件,利用此特性,可以在 __init__.py
文件中批量导入多个模块都在公用的模块,而不再需要一个一个的导入。
拿上面的demo来说,manager.py和manager2.py中都用到 time 模块,我们就其移动到 __init__.py
# __init__.py
import time
import os
import sys
import abc
在使用这些内置等模块时,首先导入包:
import animals # 导入包
# 在调用time模块时,必须使用包名+模块名的方式引用:
def recordTime(self):
#引用变为:包名animals + 模块名称
self.__t = animals.time.time()
print('feeding time for %s is %.0f'%(self.animal.name,self.__t))
self.animal.getSpeedBehavior()
.
4、 解决找不到模块的问题
我们知道Python中使用import导入需要的包,然而平时使用像vscode,pycharm这列ide时,经常出现找不到包的问题,错误信息如下:Exception has occurred: ModuleNotFoundError
No module named 'animals'
当导入模块时,解释器会按照 sys.path 列表中的目录顺序来查找导入文件。要想查看解释器目前查找的目录顺序,先导入通过sys模块,使用sys.path,如下是import时查看的目录顺序:
['/home/zglg/mywork/md...mo/animals',
'/home/zglg/anaconda3...thon37.zip',
'/home/zglg/anaconda3.../python3.7',
'/home/zglg/anaconda3...ib-dynload',
'/home/zglg/anaconda3...e-packages']
看到animals包不在解释器要查找的目录里,所以出错了。
所以需添加animals包所在的文件夹路径,其中一种修改方法如下,直接粗暴向 sys.path 中添加找不到的目录:
BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# __file__获取执行文件相对路径,整行为取上一级的上一级目录
sys.path.append(BASE_DIR)
import animals
再次启动程序,看到animals包目录已经显示搜索path列表中:
['/home/zglg/mywork/mdfiles/classdemo',
'/home/zglg/mywork/md...mo/animals',
'/home/zglg/anaconda3...thon37.zip',
'/home/zglg/anaconda3.../python3.7',
'/home/zglg/anaconda3...ib-dynload',
'/home/zglg/anaconda3...e-packages']
接下来就可以正常导入animals包,找不到包的问题解决。
以上就是此专题介绍的Python包、模块概念,以及如何应用到我们自己的实际项目的代码框架中,写出更加容易维护、可读性更好的代码。