在编写python程序的过程中,不可避免的需要自定义一些python的类和函数。有时候定义的函数太多,就要根据用途放到不同的module(模块)中去,项目更大时,需要将这些module再分类,放到不同的package(包)中,以方便管理。
可以这样理解,module就是*.py文件,里面定义了一些类,函数及变量,可以被其他程序调用;将不同的module整合到一个文件夹中,就得到了package,为了实现对其中的module的管理,package中往往需要有一个__init__.py文件。

1.最简单的方法:定义单个module

这种方法是最直观、最简单的,也是我目前为止使用频率最高的。在python中,每一个*.py文件都可以被其他的python程序所引用。如图1,在pycharm中我建立了一个python_module_test的项目:

python run module python run module和customized_python


现在里面只有两个文件:my_module.pyrun.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后,打印如下信息:

python run module python run module和customized_字符串_02


很明显,run.py脚本导入了my_module.py中的所有的变量(var1var2var3)及my_module.py中导入的包(t)。

2.如果module在文件夹中会如何?

上面的例子中,run.pymy_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文件。那么我们来实际运行一下吧:

python run module python run module和customized_python_03


这次我直接在Terminal窗口运行的python run.py命令,输出正常。那么交互式运行的结果呢?

python run module python run module和customized_python run module_04


可以看出,仍然可以运行。

这是否就说明一个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 run module python run module和customized_字符串_05


这说明,python并没有将模块module.py导入到环境中去,解决的办法,就是为包pkg添加__init__.py文件,对该包中的模块等资源进行管理。修改后的项目结构如下:

python_module_test
	├──pkg
	│	├──__init__.py	
	│	└──my_module.py
	└──run.py

其中,__init__.py的内容为:

# __init__.py
__all__=['my_module']

这时,再执行上述代码,结果如下:

python run module python run module和customized_项目结构_06


这说明,__init__.py文件中的__all__参数控制该包中哪些模块(变量)可以以from pkg import *的方式导入被导入。用户也可以在__init__.py文件中定义其他的变量、类以及函数,然后将这些名字以字符串添加到__all__列表中,这样在就可以被导入到运行环境中去。