python中类内部类的命名空间

时间:2014-10-23 16:22:59

标签: python

我试图理解python 2.7中命名空间的嵌套。

考虑以下无效代码:

class c(object):
  def debug(self):
     print globals(),locals()
     print x,y

class a(object):
   x=7 
   def __init__(self):
     self.y=9
   class b(object):
      def debug(self):
         print globals(),locals()
         print x,y
   class d(c):
      pass

如何从调用

访问变量x和y
a().b().debug()
a.b().debug()
a().d().debug()
a.d().debug()

他们似乎都看不到x和y。

编辑后讨论,似乎只能通过显式扩展嵌套类的信息来达到我想要的(避免引用全局变量)。例如

class a(object):
   #
   @classmethod
   def _initClass(cls):
     for v in dir(cls):
       if type(cls.__dict__[v])==type:
         setattr(cls.__dict__[v],'vader',cls)   
   #
   x=7 
   class b(object):
     def debug(self):
       print b.vader.x
   class d(c):
     pass

 a._initClass()

即使这种技术对于访问实例变量似乎也没有用,如a()。d()。调试序列中所预期的那样。

2 个答案:

答案 0 :(得分:4)

class个对象创建范围;类主体只执行一次并丢弃,本地命名空间生成类属性。类主体从不参与嵌套范围;在解析非本地名称时,它们会被完全忽略。

因此,您的x = 7不是嵌套b类(或其方法)可以访问的名称。相反,它是a上的类属性。访问a.x将有效。 y是一个实例属性,您必须拥有对该实例的引用,才能在其他任何位置访问它。

请注意,这也适用于class b;它现在是a类属性,就像x是类属性一样。

除了引用类对象之外,您的类b没有什么特别之处。仅仅因为您创建了a的实例并不意味着b具有任何特权访问权限; a().b()不会在实例之间创建关系。你可以这样做:

b = a.b
b_instance = b()

并没有区别。你甚至可以这样做:

a.b.a = a
a.b.a()

世界不会崩溃! (想象一下)。

答案 1 :(得分:1)

Martijn已经给出了一个很好的答案,但是我会自己捅一下。

正如Martijn所说,类声明在首次导入模块时执行时更像是一次性函数,具有自己的局部作用域。无论在本地范围内遗留下什么,在执行类声明中的所有内容之后,都将用作类的字典。因此,x__init__bd最终都成为a类对象的属性。您的班级bd也是如此;导入模块时会执行它们的实体,并且剩下的局部范围也会用作它们的字典。

您的代码不起作用的原因是,在debug方法执行时,它所知道的唯一范围是全局范围和它自己的本地范围。在python中,方法不会隐式地将类实例的字典作为其范围的一部分包含在像C ++这样的语言中。类实例显式地显示为参数列表中出现的self参数(因此,Python' sen"显式优于隐式" - 尝试import this in python控制台)。

此外,在a访问和实例化其他类bd之前,是否实例化a并不重要。{1 {}}和b都是d上的类属性。因此,python可以从a的实例或对b类对象的直接引用成功检索da