我开始编写python程序已有一段时间了,但我不是很擅长,目前我遇到了一个问题,这似乎很奇怪,至少对我而言。
假设我们有两个源文件,名为A.py
和B.py
,其内容如下:
A.py
import B
__global__ = 'not set yet'
class Data:
__var__ = 'not set yet'
def init():
global __global__
__global__ = 'value set for global'
Data.__var__ = 'value set for class var'
if __name__ == '__main__':
init()
t = B.Test()
t.display()
print '============================'
print 'global(in A): ' + __global__
print 'class var(in A): ' + Data.__var__
B.py
import A
class Test:
def __init__(self):
self.glo = A.__global__
self.var = A.Data.__var__
def display(self):
print 'global: ' + self.glo
print 'class var: ' + self.var
print '============================'
print 'global(in B): ' + A.__global__
print 'class var(in B): ' + A.Data.__var__
然后我跑了python A.py
,输出如下:
global: not set yet
class var: not set yet
============================
global(in B): not set yet
class var(in B): not set yet
============================
global(in A): value set for global
class var(in A): value set for class var
在我看来,前4个输出应该与最后2个输出一致,但事实并非如此,似乎在类和方法定义期间设置了值并且无法更改。它与许多其他语言(例如Java)非常不同。那么,任何人都可以帮忙解释一下,或者粘贴一些链接来帮助理解它吗?有没有解决方法?
提前致谢,
开尔文
==============编辑==============
感谢@icktoofay,@ shop和@RocketDonkey,在我尝试下面的代码后,我找到了根本原因:
import sys
import A
import __main__
__global__ = 'not set yet'
class Data:
__var__ = 'not set yet'
def init():
global __global__
__global__ = 'value set for global'
Data.__var__ = 'value set for class var'
if __name__ == '__main__':
init()
for key in sys.modules.keys():
if key in ['__main__', 'A']:
print key + ' : ' + sys.modules[key].__file__
print '===================='
print 'A: ' + A.__global__
print 'A: ' + A.Data.__var__
print '===================='
print __main__.__global__
print __main__.Data.__var__
输出是:
__main__ : A.py
A : D:\test\python\A.py
====================
A: not set yet
A: not set yet
====================
value set for global
value set for class var
这是因为文件A.py
导入了两次,一个名为__main__
,另一个名为A
,值在模块__main__
中更改,但对于模块{ {1}},该值来自模块B
,因此值不会更改。
我确实需要深入了解python的模块导入。 :-D
答案 0 :(得分:3)
循环导入(A
导入B
,B
导入A
)与其中一个模块是主要脚本是问题所在。
当您要求Python导入模块时,它首先查看sys.modules
以查看该名称的模块是否已存在。如果是这样,它只使用该模块。如果没有该名称的模块,它将生成一个新的模块对象,将其放在sys.modules
中,并在该模块中运行相应的Python代码。
Python脚本中使用了一种流行的习语:无处不在的
if __name__ == '__main__':
当Python想要运行主脚本时,它会导入名为__main__
的模块。
当你的主脚本与其他模块完成任务时,这是完全正常的,但是当其他模块想要再次对主模块执行操作时,会遇到麻烦:再次导入主模块的脚本可能正常导入它名称(如本例中的A
)。不幸的是,已加载的模块未命名为A
;它名为__main__
。
一个非常简单的解决方案就是删除其他模块对主模块的依赖性。那你就不会遇到这种不直观的行为。你可以这样做的一种方法是让主脚本只是一个存根,调用另一个模块的main
函数或其他东西。
另一种解决方案是让主脚本手动改变sys.modules
以将自己置于另一个名称之下。这有点hacky,但它确实有效:
sys.modules['A'] = sys.modules[__name__]
现在你知道了。
答案 1 :(得分:1)
+1给@icktoofay - 我会把更多的股票放在那个答案而不是我的,所以拿这个有一点点盐,因为我对这个过程缺乏经验的理解:
正如其他人所说,您的主要问题是循环进口。其他人会更聪明地评论,但正在发生的事情的要点是:
import B
- 只要您运行A.py`就会发生这种情况,然后您转到B.py并立即遇到导入A. A
在当前命名空间中有不同的名称,它会再次导入(为了验证这一点,在print __name__
中import B
上方添加A.py
- 您会看到两个不同的名字出现)。A
导入B
时,它会带来__global__ = 'not seen yet'
声明,因此当您说self.glo = A.__global__
时,您将获得该变量(而非修改后的A
一,因为该特定代码未在{em>此版本的A.Data.__var__
)中执行。init
相同 - 您尚未在此模块中运行A
(因为它不是您的'主'A.__global__
),因此尚未修改任何内容。A.Data.__var__
和A
也会显示“尚未看到” - 它们未经过修改且与上述变量相同。__main__
部分{{1}}中的代码正常执行,因为它在该版本的模块上运行,该版本会执行您指定的所有初始化。