2

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

假设我们有两个名为A.pyand的源文件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、@hop 和@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__,但是对于模块B,值是从模块中获取A的,所以值没有改变。

我确实需要更深入地了解python的模块导入。:-D

4

2 回答 2

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__]

现在你知道了。

于 2013-01-08T02:53:52.747 回答
1

+1 到@icktoofay - 我会在这个答案中投入比我更多的股票,所以请带上一点盐,因为这是我公认的对过程缺乏经验的理解:

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

  1. import B- 这会在您运行 A.py` 时立即发生,因此您然后转到 B.py 并立即遇到 import A。
  2. 由于A在当前命名空间中具有不同的名称,它会再次被导入(要验证这一点,请在上面添加-print __name__您会看到出现两个不同的名称)。import BA.py
  3. A被导入时B,它会带来__global__ = 'not seen yet'声明,因此当您说 时self.glo = A.__global__,您将获得该变量(而不是修改后的变量,因为该特定代码不会在版本中执行A)。
  4. A.Data.__var__- 您尚未init在此模块中运行相同(因为它不是您的 'main' A),因此尚未修改任何内容。
  5. 根据上述内容,您可以看到原因A.__global__并且A.Data.__var__还会显示“尚未看到” - 它们尚未修改并且与上面的变量相同。
  6. A在该__main__部分中的代码正常执行,因为它在该模块版本上运行,该版本确实经过了您指定的所有初始化。
于 2013-01-08T03:13:50.667 回答