在其自己的模块中更改后,从另一个模块引用的变量的值不会更改

时间:2013-01-08 02:42:51

标签: python

我开始编写python程序已有一段时间了,但我不是很擅长,目前我遇到了一个问题,这似乎很奇怪,至少对我而言。

假设我们有两个源文件,名为A.pyB.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

2 个答案:

答案 0 :(得分:3)

循环导入(A导入BB导入A)与其中一个模块是主要脚本是问题所在。

Python如何导入模块

当您要求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 - 我会把更多的股票放在那个答案而不是我的,所以拿这个有一点点盐,因为我对这个过程缺乏经验的理解:

正如其他人所说,您的主要问题是循环进口。其他人会更聪明地评论,但正在发生的事情的要点是:

  1. import B - 只要您运行A.py`就会发生这种情况,然后您转到B.py并立即遇到导入A.
  2. 由于A在当前命名空间中有不同的名称,它会再次导入(为了验证这一点,在print __name__import B上方添加A.py - 您会看到两个不同的名字出现)。
  3. A导入B时,它会带来__global__ = 'not seen yet'声明,因此当您说self.glo = A.__global__时,您将获得该变量(而非修改后的A一,因为该特定代码未在{em>此版本的A.Data.__var__)中执行。
  4. init相同 - 您尚未在此模块中运行A(因为它不是您的'主'A.__global__),因此尚未修改任何内容。
  5. 根据上述内容,您可以了解为什么A.Data.__var__A也会显示“尚未看到” - 它们未经过修改且与上述变量相同。
  6. __main__部分{{1}}中的代码正常执行,因为它在该版本的模块上运行,该版本会执行您指定的所有初始化。