Python程序中,import 语句导入一个新的模块供当前程序使用。import 的基本语法是 import module_name
; 执行 import 语句时,Python解释器首先搜索到 module_name 指向的源码文件,然后加载到内存,并将新导入的模块绑定到一个变量上;这样就可以在后续操作中,通过这个绑定的变量访问新导入的模块了。
sys.path
import module_name
时,Python 按照 sys.path
指定的文件夹列表依次进行搜索。sys.path
是一个列表类型,根据操作系统和编译参数的不同,默认存储不同的文件夹列表。另外,也可以在程序运行过程中,动态地向 sys.path
添加或删除内容,实现所需的加载模块的需求。
在当前 Arch Linux (kernel 4.19.21) 机器上,查看 Python 3.7 的 sys.path
如下:
$ python
Python 3.7.1 (default, Oct 22 2018, 10:41:28)
[GCC 8.2.1 20180831] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/lib/python37.zip', '/usr/lib/python3.7', '/usr/lib/python3.7/lib-dynload', '/home/hong/.local/lib/python3.7/site-packages', '/usr/lib/python3.7/site-packages']
sys.path
默认的第一个文件夹地址为空,指向当前的工作目录,即os.getcwd()
. 因此,搜索模块时,Python首先搜索的是当前工作目录。成功加载的模块,被放到 sys.modules
字典中;如果一个模块已经加载成功,存在于 sys.modules
中,那么下次对该模块再执行 加载操作时,就不执行搜索操作了,而是直接从 sys.modules
直接返回。
$ mkdir /tmp/demo
$ touch /tmp/demo/__init__.py #在/tmp文件夹下,创建 demo模块
$ python
>>> import os, sys
>>> import demo # /tmp目录不在sys.path中,无法加载成功
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'demo'
>>> 'demo' in sys.modules
False
>>> os.chdir('/tmp/') #改变当前工作目录到/tmp,加载成功
>>> import demo
>>> demo
<module 'demo' from '/tmp/demo/__init__.py'>
>>> demo.__path__
['/tmp/demo']
>>> 'demo' in sys.modules
True
当然,也可以通过将'/tmp'文件夹添加到 sys.path
文件夹列表,加载上述 demo
模块。
$ python
>>> import sys
>>> sys.path.append('/tmp')
>>> import demo
>>> demo
['/tmp/demo']
PYTHONPATH
除了在运行过程中修改sys.path
,我们还可以通过环境变量PYHTONPATH
来指定模块搜索的路径。Python会将 PYTHONPATH
的内容放到 sys.path
中当前工作目录''
和其他默认搜索路径之间。
$ export PYTHONPATH='/tmp'
$ python
>>> import sys
>>> sys.path
['', '/tmp', '/usr/lib/python37.zip', '/usr/lib/python3.7', '/usr/lib/python3.7/lib-dynload', '/home/hong/.local/lib/python3.7/site-packages', '/usr/lib/python3.7/site-packages']
如果要指定多个搜索路径,将它们都放到 PYTHONPATH
中即可。不同搜索路径之间需要一个分隔符进行分隔,但是因为操作系统的习惯会导致分隔符在不同系统下的差异。
$ export PYTHONPATH='/tmp:/tmp/lib2'
$ python
>>> import sys
>>> sys.path
['', '/tmp', '/tmp/lib2', '/usr/lib/python37.zip', '/usr/lib/python3.7', '/usr/lib/python3.7/lib-dynload', '/home/hong/.local/lib/python3.7/site-packages', '/usr/lib/python3.7/site-packages']
重新加载模块
如前所述,Python完成模块加载后,会将新的模块放到 sys.modules
中。如果重新加载该模块,则不同执行搜索操作,而是从 sys.modules
中直接返回。但是,有时修改了模块的源码,确实需要完全重新加载模块;这时候,只要先将保存在 sys.modules
中原模块删除,然后再执行 import
操作即可。
通过环境变量 PYTHONPATH
,加载上述demo
模块。
$ export PYTHONPATH='/tmp'
$ python
>>> import demo
>>> demo.message
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'demo' has no attribute 'message'
demo
模块中不存在message
变量,访问出错。修改demo
模块,添加message
变量。
$ echo "message='this is a message.'" > /tmp/demo/__init__.py
在Python环境重新加载demo
模块。
>>> import sys
>>> sys.modules.pop('demo')
>>> import demo
>>> demo.message
'this is a message'
网友评论