1

类 B 和 C 都派生自基类 A,并且都没有覆盖 A 的方法 test()。B与A在同一个模块中定义;C 在单独的模块中定义。调用 B.test() 打印“hello”,但调用 C.test() 失败是怎么回事?两个调用不应该最终执行 A.test() 并因此能够解析 mod1 命名空间中的符号“消息”吗?

我也很感激收到有关记录此行为的位置的提示,因为我无法找到任何东西。调用 C.test() 时如何解析名称,并且可以以某种方式将“消息”注入其中一个名称空间吗?

FWIW,我没有使用实例变量(例如 set A.message = "hello")的原因是因为我想访问一个“全局”单例对象并且不想在其中有一个明确的引用所有其他对象。

mod1.py:

import mod2

class A(object):
  def test(self):
    print message

class B(A):
  pass

if __name__ == "__main__":
  message = "hello"
  A().test()
  B().test()
  mod2.C().test()

mod2.py:

import mod1

class C(mod1.A):
  pass

输出是:

$ python mod1.py 
hello
hello
Traceback (most recent call last):
  File "mod1.py", line 14, in <module>
    mod2.C().test()
  File "mod1.py", line 5, in test
    print message
NameError: global name 'message' is not defined

非常感谢!

4

2 回答 2

2

EOL 是正确的,将程序的“主要”部分移动到新文件 mod3.py 确实可以使事情正常进行。

http://bytebaker.com/2008/07/30/python-namespaces/进一步澄清了这个问题。

在我最初的问题中,事实证明该变量message存储在__main__模块命名空间中,因为 mod1.py 正在作为脚本运行。mod2 导入 mod1,但它获得了一个单独的mod1命名空间,其中变量message不存在。下面的代码片段更清楚地展示了它写入messagemod1命名空间(不是我建议在现实生活中这样做),从而导致预期的行为。

import sys

class A(object):
  def test(self):
    print message

class B(A):
  pass

if __name__ == "__main__":
  import mod2
  message = "hello"
  sys.modules["mod1"].message = message
  A().test()
  B().test()
  mod2.C().test()

我认为最好的现实解决方法是将程序的“主要”部分移动到一个单独的模块中,正如 EOL 所暗示的那样,或者这样做:

class A(object):
  def test(self):
    print message

class B(A):
  pass

def main():
  global message
  message = "hello"
  A().test()
  B().test()

  # resolve circular import by importing in local scope
  import mod2
  mod2.C().test()

if __name__ == "__main__":
  # break into mod1 namespace from __main__ namespace
  import mod1
  mod1.main()
于 2013-03-31T13:09:57.547 回答
1

您可以使用类属性而不是全局属性吗?以下作品

import mod2

class A(object):

    message = "Hello"  # Class attribute (not duplicated in instances)

    def test(self):
        print self.message  # Class A attribute can be overridden by subclasses

class B(A):
    pass

if __name__ == "__main__":

    A().test()
    B().test()
    mod2.C().test()

不使用全局变量更简洁:在上面的代码中,message显式附加到使用它的类。


也就是说,我也很好奇为什么 globalmessage没有被mod2.C().test().

但是,如果交叉导入被删除(没有主程序mod1.py,并且没有import mod2),事情会按预期工作:导入mod1mod2mod3.py,在mod1.message = "Hello"那里做并且mod2.C().test()工作。因此,我想知道问题是否与交叉导入无关……</p>

于 2013-03-31T12:03:20.400 回答