Python导入模块的本质

为了帮助大家更好地理解导入模块,下面定义一个新的模块,该模块比较简单,所以不再为之编写测试代码。该模块代码如下(编写在 fk_module.py 文件中):

'一个简单的测试模块: fk_module'
print("this is fk_module")
name = 'fkit'
def hello():
    print("Hello, Python")

接下来,在相同的路径下定义如下程序来使用该模块:

import fk_module
print("================")
# 打印fk_module的类型
print(type(fk_module))
print(fk_module)

由于前面在 PYTHONPATH 环境变量中已经添加了点(.),因此 Python 程序总可以加载相同路径下的模块。所以,上面程序可以成功导入 fk_module 模块。

运行上面程序,可以看到如下输出结果:

this is fk_module
================
<class 'module'>
<module 'fk_module' from 'C:\\Users\\mengma\\Desktop\\fk_module.py'>

从输出结果来看,当程序导入 fk_module 时,该模块中的输出语句会在 import 时自动执行。该程序中还包含一个与模块同名的变量,该变量的类型是 module。

使用“import fk_module”导入模块的本质就是,将 fk_module.py 中的全部代码加载到内存并执行,然后将整个模块内容赋值给与模块同名的变量,该变量的类型是 module,而在该模块中定义的所有程序单元都相当于该 module 对象的成员。

下面再试试使用 from...import 语句来执行导入,例如使用如下程序来测试该模块:

from fk_module import name, hello
print("================")
print(name)
print(hello)
# 打印fk_module
print(fk_module)

运行上面程序,可以看到如下输出结果:

this is fk_module
================
fkit
<function hello at 0x0000000001E7BAE8>
Traceback (most recent call last):
  File "fk_module_test2.py", line 22, in <module>
print(fk_module)
NameError: name 'fk_module' is not defined

从上面的输出结果可以看出,即便使用 from...import 只导入模块中部分成员,该模块中的输出语句也会在 import 时自动执行,这说明 Python 依然会加载并执行模块中的代码。

使用“from fk_module import name, hello”导入模块中成员的本质就是将 fk_module.py 中的全部代码加载到内存并执行,然后只导入指定变量、函数等成员单元,并不会将整个模块导入,因此上面程序在输出 fk_module 时将看到错误提示:name 'fk module' is not defined

在导入模块后,可以在模块文件所在目录下看到一个名为“__pycache__”的文件夹,打开该文件夹,可以看到 Python 为每个模块都生成一个 *.cpython-36.pyc 文件,比如 Python 为 fk_module 模块生成一个 fk_ module.cpython-36.pyc 文件,该文件其实是 Python 为模块编译生成的字节码,用于提升该模块的运行效率。

导入同一个模块多次,Python只执行一次

先看一个例子,将本节开头处的程序文件修改成如下内容:

import fk_module
import fk_module
print("================")
# 打印fk_module的类型
print(type(fk_module))
print(fk_module)

运行结果为:

this is fk_module
================
<class 'module'>
<module 'fk_module' from 'C:\\Users\\mengma\\Desktop\\fk_module.py'>

可以看到,修改后的程序中导入了 2 次 fk_module 模块,其实完全没必要,此处导入两次只是为了说明一点:Python 很智能。虽然上面程序两次导入了 fk_module 模块,但最后运行程序,我们看到输出语句只输出一条“this is fk_module”,这说明第二次导入的 fk_module 模块并没有起作用,这就是 Python 的“智能”之处。

当程序重复导入同一个模块时,Python 只会导入一次。道理很简单,因为这些变量、函数、类等程序单元都只需要定义一次即可,何必导入多次呢?相反,如果 Python 允许导入多次,反而可能会导致严重的后果。比如程序定义了 foo 和 bar 两个模块,假如 foo 模块导入了 bar 模块,而 bar 模块又导入了 foo 模块,这似乎形成了无限循环导入,但由于 Python 只会导入一次,所以这个无限循环导入的问题完全可以避免。