在编写python程序的过程中,不可避免的需要自定义一些python的类和函数。有时候定义的函数太多,就要根据用途放到不同的module(模块)中去,项目更大时,需要将这些module再分类,放到不同的package(包)中,以方便管理。
可以这样理解,module就是*.py
文件,里面定义了一些类,函数及变量,可以被其他程序调用;将不同的module整合到一个文件夹中,就得到了package,为了实现对其中的module的管理,package中往往需要有一个__init__.py
文件。
1.最简单的方法:定义单个module
这种方法是最直观、最简单的,也是我目前为止使用频率最高的。在python中,每一个*.py
文件都可以被其他的python程序所引用。如图1,在pycharm中我建立了一个python_module_test的项目:
现在里面只有两个文件:my_module.py
和run.py
,其代码分别为:
# my_module.py
import time as t
var1 = t.time()
var2 = 'This is a long string'
var3 = 89
# run.py
from my_module import *
print(var1)
print(var2)
print(var3)
print(t.time())
在python窗口运行run.py
后,打印如下信息:
很明显,run.py
脚本导入了my_module.py
中的所有的变量(var1
、var2
、var3
)及my_module.py
中导入的包(t
)。
2.如果module在文件夹中会如何?
上面的例子中,run.py
与my_module.py
在同一级目录下,调用起来没什么问题,但如果my_module.py
在一个文件夹中,该如何处理呢?
更改项目结构如下:
python_module_test
├──pkg
│ └──my_module.py
└──run.py
然后注意修改一下run.py
中的第一代码行为from pkg.my_module import *
。
按照我在网上查的大部分资料的说法,这个时候python并不会将pkg
这个目录视为包,因为其中缺少__init__.py
文件。那么我们来实际运行一下吧:
这次我直接在Terminal窗口运行的python run.py
命令,输出正常。那么交互式运行的结果呢?
可以看出,仍然可以运行。
这是否就说明一个package中__init__.py
文件的存在与否是无关紧要的呢?显然,并不是这样的,为了说明这一点,先看一下python中有哪些导入方式。
3.python中包、模块和函数的导入方式
在上面的例子中,我们都是用的from something import *
的方式进行导入模块和变量,另外的一种导入方式就是import something as sth
。下面总结一下这两种导入方式的注意点,这里参考了这篇博客的内容。
- 方式1:
import pkg.subPkg.module as alias
如果不指定alias
,那么每次调用module
中的变量和方法时,必须全路径调用,如pkg.subPkg.module.var1
; - 方式2.0:
from pkg.subPkg import module
这种方法可以直接调用module.var1
,当然,你也可以将module
另外指定一个别名,并用别名去调用; - 方式2.1:
from pkg.subPkg.module import var1
这种方式直接导入了模块中的指定变量(函数、类等)。
总的来看,导入语句或者为import ...
的形式,或者为from ... import ...
的形式。
- 当以
import ...
的方式导入时,最终import
的内容必须为包或者模块,而不能是类、函数或变量等定义在模块中的具体内容。例如:import A.B.C
,那么A,B一定是一个package,C一定是一个package或者module。 - 当以
from ...
的方式导入时,最终import
的内容可以是包、模块或者类、函数、变量。例如:from A.B import C
,那么A一定是一个package,B可以是package,也可以是module;C可以是package、module或者变量、函数、类等任意一种。
4.__init__.py
文件的作用
from ...
导入方式中,有一种不被推荐的写法就是from A import *
,这可能会导致变量的冲突,但是当你十分清楚A中的所有模块(变量)时,这样做并没有什么问题。仍然以上文中的项目结构为例,在python命令框执行以下代码会报错:
这说明,python并没有将模块module.py
导入到环境中去,解决的办法,就是为包pkg
添加__init__.py
文件,对该包中的模块等资源进行管理。修改后的项目结构如下:
python_module_test
├──pkg
│ ├──__init__.py
│ └──my_module.py
└──run.py
其中,__init__.py
的内容为:
# __init__.py
__all__=['my_module']
这时,再执行上述代码,结果如下:
这说明,__init__.py
文件中的__all__
参数控制该包中哪些模块(变量)可以以from pkg import *
的方式导入被导入。用户也可以在__init__.py
文件中定义其他的变量、类以及函数,然后将这些名字以字符串添加到__all__
列表中,这样在就可以被导入到运行环境中去。