2020年1月3日 / 431次阅读 / Last Modified 2020年1月3日
语法
python的import语句,引入一个模块。啥是python的模块?一个.py文件就是一个模块。import module干了三件需要关注的事情。
import module会将模块及其所有的全局符号引入到当前的namespace中。一般情况下,定义的函数,类,全局变量都是全局符号,都会被引入(不管是否有下划线)。访问方式为module.name。
这也就是为什么,很多python程序的入口,放在 if __name__ == '__main__': 这个条件判断下面。因为在这个判断下面,import module时,判断条件不会成立,下面的代码不会被执行。只有python module.py直接执行的时候,__name__才等于__main__。
那么,import module时,__name__是什么呢?
我们创建一个mod.py模块,此模块内只有一行代码:
$ cat mod.py
print(__name__)
然后,我们在python解释器中试试import:
>>> import mod
mod
import module时,__name__值为module
这不是一个正常python代码应该干的事情,但是import module机制确实可以实现这样的功能。这也说明,引入符号的过程,就是代码执行的过程。只是引入的符号,代码都被包起来了(函数内,类中),没有调用的地方,就不会被真正执行。
比如有一个test_import.py模块,里面的代码如下:
$ cat test_import.py
print('12345')
a = 5
b = 6
print(a**6)
在解释器中import这个模块:
>>> import test_import
12345
15625
>>> test_import.a
5
>>> test_import.b
6
两行print都被直接执行。
sys.modules是一个dict对象,里面保存了当前python解释器执行的代码中,import的所有模块。
python解释器启动后,sys.modules里面就已经有一些模块被引入了,我理解这是python解释器自己就需要用到的模块。
>>> import sys
>>> for k,v in sys.modules.items(): print(k)
...
sys
builtins
_frozen_importlib
_imp
_thread
_warnings
_weakref
zipimport
_frozen_importlib_external
_io
marshal
posix
encodings
codecs
_codecs
encodings.aliases
encodings.utf_8
_signal
__main__
encodings.latin_1
io
abc
_abc
site
os
stat
_stat
posixpath
genericpath
os.path
_collections_abc
_sitebuiltins
readline
atexit
rlcompleter
不过,当前的namespace不能访问这些模块。需要显示的import,比如上面的import sys,我们再import几个模块看看:
>>> import time
>>> import os
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'k', 'os', 'sys', 'time', 'v']
这次当前namespace就有了sys,time,os模块(os模块已经在sys.modules中存在)可以访问。并且sys.modules里面也记录了这些模块。重要的是:这些模块的内存地址是一样的!
>>> id(os)
140461074332392
>>> id(sys.modules['os'])
140461074332392
>>>
>>> os.listdir()
['__pycache__', 'nohup.out', 'info.txt', 'test.py', 'httpd-2.4.38.tar.gz', 'httpd-2.4.38', 'ct', 'test_import.py', 'mod.py', 'jian.h', 'test.o', 'jian.o', 'text.py', 'test.c', 'jian.c', 'a.out']
>>> sys.modules['os'].listdir()
['__pycache__', 'nohup.out', 'info.txt', 'test.py', 'httpd-2.4.38.tar.gz', 'httpd-2.4.38', 'ct', 'test_import.py', 'mod.py', 'jian.h', 'test.o', 'jian.o', 'text.py', 'test.c', 'jian.c', 'a.out']
如果import一个已经在sys.modules中存在的模块,只是将sys.modules记录的地址和名称copy到当前的namespace。
>>> def test():
... import os
... print(id(os))
...
>>> test()
140461074332392
python的namespace机制,是C语言所没有的。C语言链接之后,所有的全局符号都可以相互任意访问,只要知道地址。而在python中,访问能否成功,一定要关心namespace。
刚才说了sys.modules里面保存的是import的所有模块,这包括了模块中import的其它模块,其它模块import的更多的模块......我们看一个例子,我修改了test_import.py的代码,如下:
$ cat test_import.py
import time
import argparse
import datetime
$ python3
Python 3.7.1 (default, Oct 30 2018, 20:38:04)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> len(sys.modules.keys())
35
>>> import test_import
>>> len(sys.modules.keys())
63
在python解释器中,import test_import,导致sys.modules中的模块数量暴增!我这里就不打印明细了。
-- EOF --
本文链接:https://www.pynote.net/archives/1687
《python的import module机制》有1条留言
前一篇:python编码时,长字符串如何换行?
后一篇:引入模块的全局变量未定义
©Copyright 麦新杰 Since 2019 Python笔记
模块或符号在不在内存中是一回事儿,能不能访问,要看它在不在当前的namespace中。 [ ]