Nested classes' scope?

I'm trying to understand scope in nested classes in Python. Here is my example code:

class OuterClass:
outer_var = 1
class InnerClass:
inner_var = outer_var

The creation of class does not complete and I get the error:

<type 'exceptions.NameError'>: name 'outer_var' is not defined

Trying inner_var = Outerclass.outer_var doesn't work. I get:

<type 'exceptions.NameError'>: name 'OuterClass' is not defined

I am trying to access the static outer_var from InnerClass.

Is there a way to do this?

140656 次浏览
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上的 class 属性设置为 Inner。)

如果您不使用嵌套类,那么可能会更好:

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

I think you can simply do:

class OuterClass:
outer_var = 1


class InnerClass:
pass
InnerClass.inner_var = outer_var

你遇到的问题是由于这个:

A block is a piece of Python program text that is executed as a unit. 下面是块: 一个模块、一个函数体和一个类 定义。
(...)
范围定义了名称在 一个街区。
(...)
类块中定义的名称的作用域为 限制为类块; 它不扩展到 methods – this includes generator expressions since they are 使用函数作用域实现 失败:

   class A:


a = 42


b = list(a + i for i in range(10))

Http://docs.python.org/reference/executionmodel.html#naming-and-binding

以上意思是:
函数体是一个代码块,方法是一个函数,那么在类定义中出现的函数体中定义的名称不会扩展到函数体。

对于你的情况,我这样解释:
类定义是一个代码块,那么在外部类定义中的内部类定义中定义的名称不会扩展到内部类定义。

最简单的解决办法:

class OuterClass:
outer_var = 1
class InnerClass:
def __init__(self):
self.inner_var = OuterClass.outer_var

它要求你明确,但不需要太多的努力。

In Python mutable objects are passed as reference, so you can pass a reference of the outer class to the inner class.

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)

所有的解释都可以在 Python 文档 Python 教程中找到

For your first error <type 'exceptions.NameError'>: name 'outer_var' is not defined. The explanation is:

没有引用数据属性(或其他方法)的简写从内部方法。我发现这实际上增加了方法的可读性: 在浏览一个方法时,不会混淆局部变量和实例变量。

引自 Python 教程9.4

对于第二个错误 <type 'exceptions.NameError'>: name 'OuterClass' is not defined

当类定义正常地保留(通过末尾)时,就会创建一个类对象。

引自 Python 教程9.3.1

所以当你尝试 inner_var = Outerclass.outer_varQuterclass还没有被创建,这就是为什么 name 'OuterClass' is not defined

对于第一个错误,有一个更详细但乏味的解释:

尽管类可以访问封闭函数的作用域,但是它们不起作用 作为嵌套在类中的代码的封闭范围: Python 搜索封闭函数 引用的名称,但从来没有任何封闭的类。也就是说,一个类是一个本地范围 并且可以访问封闭的本地作用域,但是它不作为封闭的本地作用域 进一步嵌套代码。

引自 学习。 Python (第五名)。马克。卢茨

class c_outer:
def __init__(self, name:str='default_name'):
self._name = name
self._instance_lst = list()
self._x = self.c_inner()


def get_name(self):
return(self._name)


def add_inner_instance(self,name:str='default'):
self._instance_lst.append(self.c_inner(name))


def get_instance_name(self,index:int):
return(self._instance_lst[index].get_name())




class c_inner:
def __init__(self, name:str='default_name'):
self._name = name
def get_name(self):
return(self._name)




outer = c_outer("name_outer")


outer.add_inner_instance("test1")
outer.add_inner_instance("test2")
outer.add_inner_instance("test3")
inner_1 = outer.c_inner("name_inner1")
inner_2 = outer.c_inner("name_inner2")
inner_3 = outer.c_inner("name_inner3")


print(outer.get_instance_name(index=0))
print(outer.get_instance_name(1))
print(outer._instance_lst[2]._name
print(outer.get_name())
print(inner_1.get_name())
print(inner_2.get_name())

Test1 test2 Test3 Name _ outer Name _ inner1 Name _ inner2 Name _ inner3