Python模块变量是如何工作的?
我以前以为,一旦一个模块被加载后,如果其他文件也导入了这个模块,或者以不同的方式导入了它,就不会再重新导入了。例如,我有一个空的文件 mdir/__init__.py
,还有一个文件 mdir/mymod.py
,内容是:
thenum = None
def setNum(n):
global thenum
if thenum is not None:
raise ValueError("Num already set")
thenum = n
def getNum():
if thenum is None:
raise ValueError("Num hasn't been set")
return thenum
在同一个文件中的前几个用例都按预期工作。这个文件是 ./usage.py
,它和 mdir
在同一个文件夹里:
import mdir.mymod
mdir.mymod.setNum(4)
print mdir.mymod.getNum()
from mdir import mymod
print mymod.getNum()
from mdir.mymod import *
print getNum()
try:
setNum(10)
except ValueError:
print "YHep, exception"
输出结果是符合预期的:
4
4
4
YHep, exception
但是,如果我对系统路径进行一些调整,看起来模块就像是被重新导入了一样:
#BEHOLD
import sys
sys.path.append("mdir")
import mymod
try:
mymod.getNum()
except ValueError:
print "Should not have gotten exception"
mymod.setNum(10)
print mymod.getNum()
print mdir.mymod.getNum()
在运行完前面的代码后,这段代码的结果是:
Should not have gotten exception
10
4
这是怎么回事呢?
1 个回答
4
mymod
和 mdir.mymod
被认为是不同的模块 - 这里有相关的讨论: http://code.djangoproject.com/ticket/3951
解释:
最好自己动手玩一下 Python 的交互式解释器,看看实际情况。我在某个目录下创建了一个名为 mydir
的文件夹(包),里面有两个文件(模块) - __init__.py
和 mymod.py
,这两个文件都是空的。我在包含 mydir
的目录下启动了 Python。现在看看会发生什么:
>>> import mydir.mymod
>>> from mydir import mymod
>>> mymod == mydir.mymod
True
为什么 mymod
和 mydir.mymod
被认为是同一个东西呢?其实这两个名字指的是同一个 模块对象 - 模块的相等性是通过它们的路径比较来决定的:
>>> mymod
<module 'mydir.mymod' from 'mydir\mymod.py'>
>>> mydir.mymod
<module 'mydir.mymod' from 'mydir\mymod.py'>
现在,如果我修改 sys.path
让它包含 mydir
,并以一种方式导入 mymod
,使得导入的模块的 路径 看起来不同:
>>> import sys
>>> sys.path.append( "d:/zrodla/stack/mydir" )
# note that importing mymod (and not mydir.mymod) prior to appending mydir to
# path would cause an error
>>> mymod2
<module 'mymod' from 'd:/zrodla/stack/mydir\mymod.pyc'>
>>> mymod2 == mydir.mymod
False
那么得到的模块对象就不会被认为是相等的。这样一个模块会被导入两次 - 这是正常的,也是 Python 的工作方式。只要记住,导入的模块是通过它们的路径来识别的 - 更具体地说,是通过“点路径”来识别的,我想 - 可以看看 sys.modules
的键:
>>> [x for x in sys.modules.keys() if "my" in x]
['mydir', 'mymod', 'mydir.mymod']
希望现在能明白了。