关于python:嵌套类的作用域?

Nested classes' scope?

我试图理解Python中嵌套类的范围。下面是我的示例代码:

1
2
3
4
class OuterClass:
    outer_var = 1
    class InnerClass:
        inner_var = outer_var

类的创建没有完成,我得到错误:

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

尝试inner_var = Outerclass.outer_var不起作用。我得到:

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

我试图从InnerClass访问静态outer_var

有办法吗?


1
2
3
4
5
6
7
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实际上是一个实例属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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。)


我认为你可以简单地做到:

1
2
3
4
5
6
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.
The following are blocks: a module, a function body, and a class
definition.
(...)
A scope defines the visibility of a name within
a block.
(...)
The scope of names defined in a class block is
limited to the class block; it does not extend to the code blocks of
methods – this includes generator expressions since they are
implemented using a function scope. This means that the following will
fail:

1
2
3
4
5
   class A:  

       a = 42  

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

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

以上是指:函数体是一个代码块,方法是一个函数,那么在类定义中存在的函数体之外定义的名称不会扩展到函数体。

为您的案例解释如下:类定义是代码块,那么在外部类定义中存在的内部类定义之外定义的名称不会扩展到内部类定义。


如果不使用嵌套类,可能会更好。如果必须嵌套,请尝试以下操作:

1
2
3
4
5
x = 1
class OuterClass:
    outer_var = x
    class InnerClass:
        inner_var = x

或者在嵌套这两个类之前声明它们:

1
2
3
4
5
6
7
class OuterClass:
    outer_var = 1

class InnerClass:
    inner_var = OuterClass.outer_var

OuterClass.InnerClass = InnerClass

(在这之后,如果需要的话,您可以使用cx1〔7〕。)


最简单的解决方案:

1
2
3
4
5
class OuterClass:
    outer_var = 1
    class InnerClass:
        def __init__(self):
            self.inner_var = OuterClass.outer_var

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


在Python中,可变对象作为引用传递,因此可以将外部类的引用传递给内部类。

1
2
3
4
5
6
7
8
9
10
11
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教程

你的第一个错误是: name 'outer_var' is not defined。解释是:

There is no shorthand for referencing data attributes (or other methods!) from within methods. I find that this actually increases the readability of methods: there is no chance of confusing local variables and instance variables when glancing through a method.

引自Python教程9.4

第二个错误是: name 'OuterClass' is not defined

When a class definition is left normally (via the end), a class object is created.

引自Python教程9.3.1

所以当你尝试inner_var = Outerclass.outer_var时,Quterclass还没有被创建,这就是name 'OuterClass' is not defined的原因。

对您的第一个错误的更详细但乏味的解释是:

Although classes have access to enclosing functions’ scopes, though, they do not act
as enclosing scopes to code nested within the class: Python searches enclosing functions
for referenced names, but never any enclosing classes. That is, a class is a local scope
and has access to enclosing local scopes, but it does not serve as an enclosing local scope
to further nested code.

引自learning.python(5).mark.lutz