为什么内部类不能在不引用python中的外部类的情况下创建自己的实例

时间:2013-06-29 20:25:22

标签: python scope nested-class

为了在我的代码中获得一些顺序,我将一个类放在另一个类中,内部类根本不需要外部类(至少这是我之前想到的)。

代码行为:

class A:
    def __init__(self):
        self.a=10
    def do(self):
        print(self.a)
        return A()
a=A()
print(a.do())
#this runs as expected with the output:
#10
#<__main__.A object at 0x01234567>

#cleaning up
del A

class B:
    #same code for class A
    class A:
        def __init__(self):
            self.a=10
        def do(self):
            print(self.a)
            return A()
a=B.A()
print(a.do())
#This raises for the line 'return A()' a NameError: global name 'A' is not defined

我无法理解为什么在这种情况下A无法从内部访问。

这是另一件类似且运行正常的事情:

def f():
    a=10
    class C:
        def __init__(self):
            pass
        def do(self):
            print(a)
            return C()
    return C().do()
print(f())

附加问题:在这种情况下,为什么班级的行为与行为不同,我们从中获得的好处是什么?

2 个答案:

答案 0 :(得分:1)

你应该用这个:

return B.A()

由于类A不是全局变量,因此它是类B的属性。类本身就是名称空间,即在类中定义的所有对象实际上都成为它的属性。

class B:
    #same code for class A
    class A:
        def __init__(self):
            self.a=10
        def do(self):
            print(self.a)
            return B.A()

>>> B.A
<class __main__.A at 0x9f3ea1c>
>>> a = B.A()
>>> print(a.do())
10
<__main__.A instance at 0x9fd7aec>

代码2:

def f():
    a=10
    class C:
        def __init__(self):
            pass
        def do(self):
            print(a)
            return C()
    return C().do()
print(f())

这个代码与嵌套的第一类完全不同。函数不会创建新的命名空间,只是创建一个新的范围。

因此,类C只是一个用于f()的局部变量,这就是为什么在return C()内调用do()才能正常工作。

教程:

http://docs.python.org/2/tutorial/classes.html

http://docs.python.org/2/tutorial/controlflow.html#defining-functions

答案 1 :(得分:1)

只有在类体内直接访问类变量才是非限定的。

当查找变量名称时,该过程有效this way(假设没有globalnonlocal声明):

  1. 查看当前范围(类或函数或全局)
  2. 如果找不到
  3. ,则在外部封闭的函数范围
  4. 中递归查看
  5. 如果找不到,请查看全局范围
  6. 如果找不到,请查看内置范围
  7. 在块的执行过程中,无论是函数定义还是类体,对象本身还不存在,所以显然你不能引用它。

    让我们看看如果在绑定算法中将类计入封闭范围,可能会发生什么:

    x=3
    class A:
        def __init__(self):
            A.x = 5
    
        def foo(self):
            print(x)
    
    a=A()
    a.foo()
    

    类定义中A.x没有绑定,因此print(x)必须引用全局x,对吧?但是当调用a.foo()时, 要引用A.x。这不直观。与类范围不同,函数作用域是不可变的(实际上是不可访问的)。

    此外,除了classvarglobal之外,您还需要nonlocal声明。它只适用于当前类,因此您还需要nonlocal classvar语句...

    我认为类不被视为“封闭范围”的另一个原因是允许class creation customization使用元类。但我不确定,