120

我试图了解 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_varInnerClass.

有没有办法做到这一点?

4

7 回答 7

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

于 2009-11-19T18:58:53.827 回答
45

我认为你可以简单地做:

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

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

为您的情况解释一下:
类定义是一个代码块,然后在外部类定义中存在的内部类定义之外定义的名称不会扩展到内部类定义。

于 2011-12-03T09:26:51.033 回答
20

如果你不使用嵌套类,你可能会更好。如果你必须嵌套,试试这个:

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如果需要,您可以。)

于 2009-11-19T19:19:33.470 回答
3

最简单的解决方案:

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

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

于 2013-12-27T19:51:34.263 回答
1

在 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)
于 2016-07-18T13:37:22.653 回答
0

所有解释都可以在Python 文档 The Python Tutorial

对于您的第一个错误<type 'exceptions.NameError'>: name 'outer_var' is not defined。解释是:

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

引自The Python Tutorial 9.4

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

当一个类定义正常离开时(通过结束),一个类对象被创建。

引自The Python Tutorial 9.3.1

因此,当您尝试时inner_var = Outerclass.outer_varQuterclass尚未创建,这就是为什么name 'OuterClass' is not defined

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

尽管类可以访问封闭函数的作用域,但是,它们并不充当嵌套在类中的代码的封闭作用域:Python 搜索封闭函数以查找引用的名称,但从不搜索任何封闭类。也就是说,一个类是一个局部作用域,并且可以访问封闭的局部作用域,但它不能用作进一步嵌套代码的封闭局部作用域。

引自Learning.Python(5th).Mark.Lutz

于 2017-03-22T07:08:05.997 回答
0
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

于 2021-10-05T06:59:19.773 回答