当我在类代码块中使用任何类变量时,我没有定义错误。我该如何解决?
例如
class A():
__hidden_number__ = 5
__no_hidden_number__ = A.__hidden_number__ + 4 # to cause error. why ?
感谢。
答案 0 :(得分: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 :(得分:2)
由于这可能有点不清楚(现有答案很好),让我补充一点:
class A:
pass
A = type('A', (object,), {})
我们在类声明中编写的内容实际上是构建那个(此处为空)字典,并且在变量A
被赋值之前发生。而且由于我们还没有 - 在类声明运行时命名空间层次结构中名称A
的变量,A
不可用。
该类存在,它还具有类型名称 'A'
,但尚未将其分配给变量A
。
class A: pass
- 版本和显式type
调用之间的区别是语法糖:使用class
时,嵌套在类中的所有内容都会自动命名为类字典。
这就是为什么这样做的原因:
class A:
var = 1
var2 = var + 1
但是正如我们上面所看到的,最终将保存我们的新类的局部变量A
仅在类声明已被评估之后才被分配,因此在其中不可用。
如果我们反汇编一个类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
由于代码对象必须返回值,因此会自动添加 19
和22
。我们可以忽略这些例子。
这里还发生了什么?
0
:将字符串'A'
推入堆栈。这将成为类的名称(type()
的第一个参数)。3
:推送一个空元组,即父类列表6
:加载类声明的代码对象。9
和12
运行类声明代码对象。这就是例如做我们的(类)变量赋值。它返回类字典。15
将类构建到堆栈中。这相当于type('A', (), class_dict)
,其中参数恰好是此时堆栈上的值。最后:
16
将新创建的类存储在名为A
的本地名称空间中。正如我们所看到的,在将类分配给变量12
(A
)之前,将运行类声明(16
)。
请注意,Python 3中的反汇编是不同的,因为python是一个特殊的内置class builder function。
是的,这是一个太长的答案; - )。