当跨模块派生类时,名称解析如何工作?

时间:2013-03-31 11:43:29

标签: python python-2.7

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

我也很感激地收到关于这种行为记录在哪里的提示,因为我无法发现任何事情。调用C.test()时如何解析名称,并且可以以某种方式将“message”注入其中一个名称空间?

FWIW,我没有使用实例变量的原因(例如,设置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

非常感谢!

2 个答案:

答案 0 :(得分:2)

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

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

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

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()

答案 1 :(得分: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显式附加到它所使用的类中。


尽管如此,我也非常好奇为什么message找不到全球mod2.C().test()

事情按预期工作,如果删除了交叉导入mod1.py中没有主程序,没有import mod2):导入mod1和来自mod2的{​​{1}},mod3.py那里和mod1.message = "Hello"有效。因此,我想知道问题是否与交叉导入无关......