2017-09-12 34 views
1

当我在类代码块中使用任何类变量时,我得到未定义的错误。我该如何解决它?Python为什么我没有定义错误?

例如

class A(): 
    __hidden_number__ = 5 
    __no_hidden_number__ = A.__hidden_number__ + 4 # to cause error. why ? 

感谢。

+1

尝试'__no_hidden_​​number__ = __hidden_​​number__ + 4' –

+0

因为'A'尚未定义。 –

+1

@ juanpa.arrivillaga nope。你在'A'范围内。你指的是'A.A'。检查我的答案并测试片段。 –

回答

4

你的类变量已经在A命名空间中。

所以,你只需要做:

__no_hidden_number__ = __hidden_number__ + 4 

否则你试图访问A.A,它还不存在。

为了说明什么,我指出,该“工程”(而不是你想要的):

class A(): 
    class A(): 
     __hidden_number__ = 4 
    __no_hidden_number__ = A.__hidden_number__ + 4 
A() # that works 

认为不会:

class A(): 
    class B(): 
     __hidden_number__ = 4 
    __no_hidden_number__ = A.__hidden_number__ + 4 # B.__... would've worked 
A() # beeep: NameError: name 'A' is not defined 

注意,你应该避免定义带有双下划线的私人属性(__xxx__)。它可以工作,但这通常是为python特殊类成员(__class____file____eq__等)保留的。名称修改(使对象成为“私有”)已经以2个前导下划线出现。

+1

注意问题是*为什么*错误出现。那么'A'在类声明完成之前没有定义。 – dhke

+0

@ Jean-FrançoisFabreErm?是?名称'A'在类声明后严格分配。 – dhke

+0

尝试我的代码片段,然后通过'B'更改内部'A',看看会发生什么 –

2

由于这可能是一个有点不清楚(现有的答案是罚款),让我补充到:

class A: 
    pass 

is equivalent to

A = type('A', (object,), {}) 

我们写的类声明里面有什么本质上是建立(这里是空的)字典,并且发生之前变量A被分配。而且,由于我们还没有 - 名称空间层次结构中名称为A的变量,而类声明运行时,A不可用。

的类存在,它也有类型名称'A',但目前还没有得到赋值给变量A,但。

class A: pass -version和明确type调用之间的区别是语法糖:使用class,一切都嵌套在类中被自动命名空间到类字典。

这就是为什么这个工程:

class A: 
    var = 1 
    var2 = var + 1 

但我们可以在上面看到,局部变量A,将最终持有类的声明已经被评估后,才我们的新类被分配,因此ISN” t可用于其内部。

如果我们拆开一类DECL,我们得到:

import codeop, dis 
    dis.disassemble(codeop.compile_command('class A:\r\n pass')) 

1   0 LOAD_CONST    0 ('A') 
      3 LOAD_CONST    3 (()) 
      6 LOAD_CONST    1 (<code object A at 0x80076ff30, file "<input>", line 1>) 
      9 MAKE_FUNCTION   0 
      12 CALL_FUNCTION   0 
      15 BUILD_CLASS   
      16 STORE_NAME    0 (A) 
      19 LOAD_CONST    2 (None) 
      22 RETURN_VALUE 

1922会自动添加,因为代码对象必须返回一个值。我们可以忽略这些例子。

这里还发生了什么?

  • 0:将字符串'A'推到堆栈上。这将成为班级的名字(type()的第一个参数)。
  • 3:推一个空元组,母类的列表
  • 6:加载类声明的代码对象。
  • 912运行类声明代码对象。这是例如做我们的(类)变量分配。它返回类字典。
  • 15将该类构建到堆栈上。这相当于type('A',(), class_dict),其中参数恰好是堆栈中此时的值。

最后:

  • 16店刚创建的类到名称A下的局部命名空间。

我们可以看到,在类声明运行(12),前级分配给它的可变A16)。

请注意,在Python 3中反汇编是不同的,因为python作为特殊的内建函数class builder function

是的,这是一个太长的答案;-)。

+0

现在我明白了。这只是因为它正在构建中而不能成为相同的“A”。所以我们都是对的。你的回答是我忽略的一个很好的附加组件。 –

+0

@ Jean-FrançoisFabre我并不是想说你错了,但细节有点讨厌。 Python是一个堆栈机器,区分“堆栈中的类型对象”A''和“名称为'A的变量来保存该类型对象”在这里有所不同。 – dhke

相关问题