在此之前,我们运行一些简短的Python代码,都是通过Python解释器(python或ipython)进行的,如果我们退出解释器再重新运行解释器后,上次敲进去的变量、函数等都不见了,没有保存下来。为了保存我们曾经写过的代码,就是要写成.py
文件,称为脚本
。
如果你这个脚本想要使用其它脚本里面的变量、函数和类也是可以的,在你这个脚本里面用import
来导入要引用的脚本,而那个被引用的脚本就称作模块(module)
。
简单来说,一个Python源码文件(*.py)就是一个模块。
我们的第一个Python模块
接下来,我们用文本编辑器(比如,前面介绍的VS Code)来创建一个名为 my_first_module.py
的文件作为我们编写的第一个模块:
#!/usr/bin/env python3
# coding:utf-8
# Author: veelion
# file name: my_first_module.py
'''My First Module'''
MY_NAME = 'My_First_Module'
def my_print(a):
print(MY_NAME, ' print', a)
def my_add(a, b):
return a+b
我们的第一个Python模块里面有一个全局变量:MY_NAME
,两个函数:my_print()
和my_add()
。接着我们在这个文件所在目录
运行Python解释器ipython:
In [1]: import my_first_module
In [2]: my_first_module?
Type: module
String form: <module 'my_first_module' from '/home/veelion/p2/tutorial/md_Python/codes/my_first_module.py'>
File: ~/p2/tutorial/md_Python/codes/my_first_module.py
Docstring: My First Module
In [3]: my_first_module.MY_NAME
Out[3]: 'My_First_Module'
In [4]: my_first_module.my_add(2, 3)
Out[4]: 5
In [5]: my_first_module.my_print('猿人学')
My_First_Module print 猿人学
导入模块用import
,模块名称就是文件名my_first_module.py
去掉文件后缀.py
后的名字。从上面ipython的使用中,我们可以看到模块中的函数、变量都是可以被拿来用的。
注意: Python模块的文件名只能是字母、数字和下划线,不能有-,+
等其它符号,否则导入会报错,原因很简单,比如-
符号会和Python里面的减号混淆。
把上面的模块重命名为my-first-module.py
,再import
导入一下看看:
In [6]: import my-first-module
File "<ipython-input-6-a8306ca40c5e>", line 1
import my-first-module
^
SyntaxError: invalid syntax
Python模块的二三事
(1)模块可以包含可执行的全局语句。这些语句应该是用于初始化该模块,它们只在第一次被import
时执行。我们来举个例子,创建两个只包含一句print
的模块:
# m1.py
print('m1 is imported')
# m2.py
import m1
print('m2 is imported')
在main.py
中导入m1
和m2
这两个模块:
import m1
import m2
import m1
print('I am main.py')
这里m1
被显性导入两次,还有一次被m2
阴性导入,一共导入三次,那么是不是m1 is imported
会被打印3次呢?我们运行这个脚本试试看: python main.py
。猜猜运行结果是怎样的?
m1 is imported
m2 is imported
I am main.py
结果是只被打印了一次。这就是只在第一次被import
时执行的意思。再试试把main.py
中的两个import m1
都去掉,只import m2
会是什么结果?
(2)每个模块都都它自己私有的符号表,它被当做全局符号表被该模块中所有函数使用,也就是说,每个模块都有自己的名字空间。因此,模块里面可以尽情(如有必要)使用全局变量,而不用担心它们与模块使用者的全局变量冲突。用户使用模块中的全局变量也很简单:modname.itemname
。
比如,my_first_module
模块中的MY_NAME
使用时就是my_first_module.MY_NAME
,而在你自己的脚本里面同样可以命名MY_NAME
的全局变量,而不会和my_first_module
里面的冲突。
(3)模块可以import
其它模块。模块导入语句import
不一定要在脚本的最开始,可以在代码其它位置需要时导入。当然,在最开始导入是最清晰、规范的做法。
import 模块的各种方式
我们使用import
的方式很多,前面那种 import module_name
的方式是最常用的,也是代码规范推崇的用法。从语法上讲还有其它方式:
(1)用from导入部分:
In [1]: from my_first_module import my_add
In [2]: my_add(1,3)
Out[2]: 4
In [3]: my_print('hi')
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-3-b42bb20df9e4> in <module>
----> 1 my_print('hi')
NameError: name 'my_print' is not defined
In [4]: my_first_module.my_add(1,2)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-4-df5ce230b443> in <module>
----> 1 my_first_module.my_add(1,2)
NameError: name 'my_first_module' is not defined
通过from modname import xxx
的方式,我们只导入了my_add
,调用my_print
就会出错。并且,my_first_module
模块名称也是未定义的,即没有被导入。
(2)用from导入部分并重命名
跟(1)一样,只不过把导入的名称起了别名而已,使用时用别名:
from my_first_module import my_add as myadd
(3)用from导入全部
In [1]: from my_first_module import *
In [2]: my_add(1,2)
Out[2]: 3
In [3]: my_print('猿人学')
My_First_Module print 猿人学
In [4]: MY_NAME
Out[4]: 'My_First_Module'
这种方式看似简单,写代码时省去了模块名称my_first_module
这个前缀。但是,这个省略带来很大隐患,会限制我们自己命名。如果我们自己命名和模块里面的名称一样,就会覆盖模块里面的名字。
这种import的方式是代码规范严禁杜绝的
(4)重命名模块
如果模块名称很长,我们可以给它起个短一点的别名,这样写代码会简单些:
In [1]: import my_first_module as mfm
In [2]: mfm.my_add(1,2)
Out[2]: 3
In [3]: mfm.my_print('猿人学')
My_First_Module print 猿人学
In [4]: mfm.MY_NAME
Out[4]: 'My_First_Module'
这个和import my_first_module
实际上一样,只是使用的名称变为mfm
。模块的别名可以任意起,只要和其它名称区分开来就好。
(5)模块重新加载
我们写完一个模块,可能要通过Python解释器(如ipython)进行验证一下,于是运行Python解释器,import模块,发现模块的某个函数有错误,就在编辑器修改了该函数并保存该模块文件。继续在刚才打开的解释器里面验证那个有错误的函数,发现刚才的修改没生效,竟然没有生效!!!
为什么呢?为了效率,每个解释器导入的模块只导入一次。因此,如果你中途修改了模块,就要出解释器重新进入并重新导入模块才能使修改生效。如果不退出解释器而重新导入模块,不管你运行多少次import modname
都是无效的,因为解释器一看这个模块已经导入过了,就不费劲再导入一次了。解释器懒,你就不能懒。
或者,可以不重新启动解释器而使用importlib.reload()
重新导入。
把Python模块当做脚本运行
任何Python文件都可以这样来运行:
python3 file.py
一个文件的Python模块当然也可以这样运行。一个Python文件,前面是函数的定义,定义完要运行,我们就要写调用语句,最初你相到的可能是这样的:
# Author: veelion
# file: mylib.py
def add(a, b):
return a+b
print(add(2, 3))
通过python mylib.py
运行一下,就可以得到运行结果。
目前看起来一切正常,你看看有没有问题?
回头看看上面模块二三事的第(1)条,如果这个文件当做模块被其它文件import
时,是不是也会运行打印语句?这条打印语句往往是我们为了验证add()
函数而进行的,属于测试阶段的代码,而交付给他人作为模块使用时,它是不需要的。那么,该怎么办?
通过__name__
属性就可以来限制print(add(2, 3))
语句的运行。文件作为脚本运行时,它的__name__
属性是__main__
,而作为模块被import时,它的__name__
属性是模块的名称。
先看看模块被import时的__name__
:
In [24]: import mylib
5
In [25]: mylib.__name__
Out[25]: 'mylib'
我们可以看到,import mylib
后打印出了5
,也就是运行了print(add(2, 3))
语句。
然后,我们修改mylib.py
文件,把测试语句修改一下:
# Author: veelion
# file: mylib.py
def add(a, b):
return a+b
if __name__ == '__main__':
print(add(2, 3))
再次在ipython解释器里面导入该模块时就不会打印出5
,也就是那句print不再执行。
而在命令行下运行python3 mylib.py
这个脚本就会执行那句print语句,因为这种执行方式下,模块的__name__
为__main__
。
这些用__name__ == '__main__'
条件判断的代码通常是该模块的测试代码,或者是如何使用该模块的示例代码。
Python模块总结
(1)一个Python文件就是一个模块;
(2)一个模块可以import其它模块;
(3)在Python解释器运行中,一个模块只可以被import一次,除非使用importlib.reload();
(4)模块中的可执行语句(非函数、类的定义)仅在该模块被import时执行一次。
(5)import模块的方式有多种,要使用最规范的方式。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。