我试图理解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和ya().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()。调试序列中所预期的那样。
答案 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所说,类声明在首次导入模块时执行时更像是一次性函数,具有自己的局部作用域。无论在本地范围内遗留下什么,在执行类声明中的所有内容之后,都将用作类的字典。因此,x
,__init__
,b
和d
最终都成为a
类对象的属性。您的班级b
和d
也是如此;导入模块时会执行它们的实体,并且剩下的局部范围也会用作它们的字典。
您的代码不起作用的原因是,在debug
方法执行时,它所知道的唯一范围是全局范围和它自己的本地范围。在python中,方法不会隐式地将类实例的字典作为其范围的一部分包含在像C ++这样的语言中。类实例显式地显示为参数列表中出现的self
参数(因此,Python' sen"显式优于隐式" - 尝试import this
in python控制台)。
此外,在a
访问和实例化其他类b
和d
之前,是否实例化a
并不重要。{1 {}}和b
都是d
上的类属性。因此,python可以从a
的实例或对b
类对象的直接引用成功检索d
和a
。