问题:嵌套类的范围?
我试图了解Python嵌套类中的作用域。这是我的示例代码:
class OuterClass:
outer_var = 1
class InnerClass:
inner_var = outer_var
类的创建未完成,并且出现错误:
<type 'exceptions.NameError'>: name 'outer_var' is not defined
尝试inner_var = Outerclass.outer_var
不起作用。我得到:
<type 'exceptions.NameError'>: name 'OuterClass' is not defined
我正在尝试从访问静态outer_var
信息InnerClass
。
有没有办法做到这一点?
回答 0
class Outer(object):
outer_var = 1
class Inner(object):
@property
def inner_var(self):
return Outer.outer_var
这与其他语言中的类似功能不太一样,并且使用全局查找而不是限制对的访问outer_var
。(如果更改名称Outer
绑定到的对象,则此代码将在下次执行该对象时使用该对象。)
相反,如果您希望所有Inner
对象都具有对的引用,Outer
因为outer_var
它实际上是实例属性:
class Outer(object):
def __init__(self):
self.outer_var = 1
def get_inner(self):
return self.Inner(self)
# "self.Inner" is because Inner is a class attribute of this class
# "Outer.Inner" would also work, or move Inner to global scope
# and then just use "Inner"
class Inner(object):
def __init__(self, outer):
self.outer = outer
@property
def inner_var(self):
return self.outer.outer_var
请注意,嵌套类在Python中并不常见,并且不会自动暗示类之间的任何特殊关系。您最好不要嵌套。(您仍然可以设置一个类属性上Outer
到Inner
,如果你想要的。)
回答 1
我认为您可以做到:
class OuterClass:
outer_var = 1
class InnerClass:
pass
InnerClass.inner_var = outer_var
您遇到的问题是由于以下原因:
块是作为单元执行的一段Python程序文本。以下是块:模块,函数体和类定义。
(…)
范围定义了块中名称的可见性。
(…)
在类块中定义的名称范围仅限于该类块;它不会扩展到方法的代码块–包括生成器表达式,因为它们是使用函数范围实现的。这意味着以下操作将失败:class A: a = 42 b = list(a + i for i in range(10))
http://docs.python.org/reference/executionmodel.html#naming-and-binding
上面的意思是:
一个函数体是一个代码块,一个方法是一个函数,那么在类定义中存在于该函数体之外的名称将不会扩展到该函数体。
用您的情况解释一下:
类定义是一个代码块,然后在外部类定义中存在的内部类定义之外定义的名称不会扩展到内部类定义。
回答 2
如果您不使用嵌套类,则可能会更好。如果必须嵌套,请尝试以下操作:
x = 1
class OuterClass:
outer_var = x
class InnerClass:
inner_var = x
或在嵌套它们之前声明两个类:
class OuterClass:
outer_var = 1
class InnerClass:
inner_var = OuterClass.outer_var
OuterClass.InnerClass = InnerClass
(在此之后,您可以del InnerClass
根据需要。)
回答 3
最简单的解决方案:
class OuterClass:
outer_var = 1
class InnerClass:
def __init__(self):
self.inner_var = OuterClass.outer_var
它要求您保持明确,但不需要花费很多精力。
回答 4
在Python中,可变对象作为引用传递,因此您可以将外部类的引用传递给内部类。
class OuterClass:
def __init__(self):
self.outer_var = 1
self.inner_class = OuterClass.InnerClass(self)
print('Inner variable in OuterClass = %d' % self.inner_class.inner_var)
class InnerClass:
def __init__(self, outer_class):
self.outer_class = outer_class
self.inner_var = 2
print('Outer variable in InnerClass = %d' % self.outer_class.outer_var)
回答 5
所有说明都可以在Python文档中找到。
对于您的第一个错误<type 'exceptions.NameError'>: name 'outer_var' is not defined
。解释是:
没有从方法内部引用数据属性(或其他方法!)的捷径。我发现这实际上提高了方法的可读性:浏览方法时,不会混淆局部变量和实例变量。
引自《 Python教程9.4》
对于第二个错误 <type 'exceptions.NameError'>: name 'OuterClass' is not defined
当正常保留类定义时(通过结尾),将创建一个类对象。
引自Python教程9.3.1
因此,当您尝试时inner_var = Outerclass.outer_var
,Quterclass
尚未创建,这就是为什么name 'OuterClass' is not defined
有关第一个错误的更详细但乏味的解释:
尽管类可以访问封闭函数的作用域,但是它们不能充当嵌套在类内的代码的封闭作用域:Python在封闭函数中搜索引用的名称,但从不搜索任何封闭类。也就是说,一个类是一个局部作用域,可以访问封闭的局部作用域,但不能用作进一步嵌套代码的封闭的局部作用域。
引用自Learning.Python(5th).Mark.Lutz