Andy Hayden 的回答为您提供了必要的解决方案,但我认为您可能会欣赏更多专门针对您的问题的背景知识。请注意,这描述了所谓的“新”对象模型,尽管旧模型(从 pre-2.2 天开始,仍然是 Python 2 中的默认值,操作几乎相同)。
当解释器编译一个类时,会读取整个类主体并将定义(在您的情况下为someFunction 和__init__)保存在字典中。它构建一个“基类”列表(它继承的类),然后调用该类的 metaclass(除非您采取特殊措施,在 Python 中,您的类的元类将是内置的键入 type) 并使用类名、基类列表和表示类名称空间的字典作为参数。
在 Python 3 中,新模型是默认模型,您可以使用 class 声明的关键字参数设置类的元类。这使您可以验证我的断言。考虑以下程序:
class print_args(type):
def __new__(cls, name, bases, name_space):
print("class:", cls)
print("Declaring class", name)
print("Bases:", bases)
print("Namespace:", name_space)
return type.__new__(cls, name, bases, name_space)
class A: pass
class B: pass
print("Defining C")
class C(A, B, metaclass=print_args):
CVar = "class attribute"
def myMethod(self, a):
return self.N, self.CVar
def __init__(self, N):
self.N = N
print("Creating c")
c = C(42)
print(c.CVar, C.CVar)
print(C.__dict__)
print(c.__dict__)
c.CVar = "instance attribute"
print(c.CVar, C.CVar)
print(c.__dict__)
print_args 类是一个简单的元类,它通过从 type 继承并在打印后将实际工作委托给 type.__new__ 来模仿 type 的操作。当C 类被声明时,它会输出
Defining C
class: <class '__main__.print_args'>
Declaring class C
Bases: (<class '__main__.A'>, <class '__main__.B'>)
Namespace: {'__qualname__': 'C', '__module__': '__main__', '__init__': <function C.__init__ at 0x10778bbf8>, 'myMethod': <function C.myMethod at 0x10778bc80>, 'CVar': 'class attribute'}
请注意,这一切都发生在声明 C 类时 - 您可以通过下一行输出来判断这一点。另请注意,打印的值告诉您传递给type.__new__ 的内容。程序接下来创建一个C 实例,并演示类属性也可以作为实例属性访问——方法解析顺序也适用于属性查找——事实上,该实例也可以访问A 和B classes 有没有。
Creating c
class attribute class attribute
此时C 类的__dict__ 如下所示:
{'CVar': 'class attribute',
'__module__': '__main__',
'__doc__': None,
'__init__': <function C.__init__ at 0x10778bbf8>,
'myMethod': <function C.myMethod at 0x10778bc80>}
其实例的字典如下所示:
{'N': 42}
它只包含实例属性N。但是在将值绑定到c.CVar 之后,我们可以看到实例属性现在与类属性不同。
instance attribute class attribute
更新后的实例__dict__ 确认了这一点。
{'CVar': 'instance attribute', 'N': 42}
希望这能让您更深入地了解声明类时会发生什么,以及实例和类之间的关系。