To be practice!
简单模块
- 最简单的模块化方式,就是把函数、类、常量拆分到不同的文件,把它们放在同一个文件夹,然后使用from your_file import function_name,class_name的方式调用。之后,这些函数和类就可以在文件内直接使用了。
1
2
3
4# utils.py
def get_sum(a, b):
return a + b
1 | # class_utils.py |
1 | # main.py |
但是所有文件都堆在一个文件夹下也并不是办法,于是,我们试着建一些子文件夹:1
2
3
4# utils/utils.py
def get_sum(a, b):
return a + b
1 | # utils/class_utils.py |
1 | # src/sub_main.py |
我们的文件结构是下面这样的:
1
2
3
4
5
6
7.
├── utils
│ ├── utils.py
│ └── class_utils.py
├── src
│ └── sub_main.py
└── main.pymain.py调用子目录的模块时,只需要使用.代替/来表示子目录,utils.utils表示utils 子文件夹下的utils.py模块就行。
- 如果我们想调用上层目录呢?注意,sys.path.append(”..”)表示将当前程序所在位置向上提了一级,之后就能调用utils的模块了。
- 同时要注意一点,import 同一个模块只会被执行一次,这样就可以防止重复导入模块出现问题。当然,良好的编程习惯应该杜绝代码多次导入的情况。
- 你可能在许多教程中看到过这样的要求:我们还需要在模块所在的文件夹新建一个_initpy,内容可以为空,也可以用来表述包对外暴露的模块接口。不过,事实上,这是Python2的规范。在Python3规范中,_init.py并不是必须的,很多教程里没提过这一点,或者没讲明白,我希望你还是能注意到这个地方。
项目模块化
使用绝对路径来导入文件
例子:使用Pycharm,项目结构如下:1
2
3
4
5
6
7.
├── proto
│ ├── mat.py
├── utils
│ └── mat_mul.py
└── src
└── main.py
1 | # proto/mat.py |
1 | # utils/mat_mul.py |
1 | # src/main.py |
- 这个例子和前面的例子长得很像,但请注意uti1s/mat_mul.py,你会发现,它import Matrix的方式是from proto.mat。这种做法,直接从项目根目录中导入,并依次向下导入模块mat.py中的Matrix,而不是使用..导入上一级文件夹。
Python解释器在遇到import的时候,它会在一个特定的列表中寻找模块。这个特定的列表,可以用下面的方式拿到:
1
2
3
4
5
6
7import sys
print(sys.path)
########## 输出 ##########
['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages']可以看到第一项为空,而Pycharm会将这一项设置为项目根目录的绝对地址,这样在运行main.py时实际上是从根目录去找相应的包的。
- 在普通Python运行环境中,可以通过修改 PYTHONHOME 来实现绝对路径的添加。Python的Virtual Environment(虚拟运行环境),可以通过Virtualenv工具,非常方便地创建一个全新的Python运行环境。这样能够打造一个独立的运行环境来保持包和模块的纯净性。
- 在一个Virtual Environment里,你能找到一个文件叫activate,在这个文件的末尾,填上下面的内容, 在每次通过activate激活这个运行时环境的时候,它就会自动将项目的根目录添加到搜索路径中去。
1
export PYTHONPATH="/home/ubuntu/workspace/your_projects"
- 在一个Virtual Environment里,你能找到一个文件叫activate,在这个文件的末尾,填上下面的内容, 在每次通过activate激活这个运行时环境的时候,它就会自动将项目的根目录添加到搜索路径中去。
神奇的 if name == ‘main‘
- Python是脚本语言,和C++、Java最大的不同在于,不需要显式提供main()函数入口
1
2
3
4
5.
├── utils.py
├── utils_with_main.py
├── main.py
└── main_2.py
1 | # utils.py |
1 | # utils_with_main.py |
1 | # main.py |
1 | # main_2.py |
- import在导入文件的时候,会自动把所有暴露在外面的代码全都执行一遍。因此,如果你要把一个东西封装成模块,又想让它可以执行的话,你必须将要执行的代码放在’
if __name==__main__
下面。 - 其实,
__name__
作为Python的魔术内置参数,本质上是模块对象的一个属性。我们使用import 语句时,__name__
就会被赋值为该模块的名字,自然就不等于__main__
了。
from module_name import *和import module_name 的区别:
- from module_name import * 会把 module 中所有的函数和类全拿过来,如果和其他函数名类名有冲突就会出问题;
- import model_name 也会导入所有函数和类,但是调用的时候必须使用 model_name.func 的方法来调用,等于增加了一层 layer,有效避免冲突。