Python模块变量是如何工作的?

2 投票
1 回答
609 浏览
提问于 2025-04-16 03:14

我以前以为,一旦一个模块被加载后,如果其他文件也导入了这个模块,或者以不同的方式导入了它,就不会再重新导入了。例如,我有一个空的文件 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

mymodmdir.mymod 被认为是不同的模块 - 这里有相关的讨论: http://code.djangoproject.com/ticket/3951

解释:

最好自己动手玩一下 Python 的交互式解释器,看看实际情况。我在某个目录下创建了一个名为 mydir 的文件夹(包),里面有两个文件(模块) - __init__.pymymod.py,这两个文件都是空的。我在包含 mydir 的目录下启动了 Python。现在看看会发生什么:

>>> import mydir.mymod
>>> from mydir import mymod
>>> mymod == mydir.mymod
True

为什么 mymodmydir.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']

希望现在能明白了。

撰写回答