Python类成员查找的底层机制
在Python中,如果我定义了三个类:
class A:
name = 'oliver'
hailstone_ending = [4,2,1]
class B:
def __init__(self):
self.name = 'oliver'
self.hailstone_ending = [4,2,1]
class C:
pass
c = C()
c.name = 'oliver'
c.hailstone_ending = [4,2,1]
那么在背后,这些类的成员查找方式是一样的吗?看起来,A
只需要一个字典就能查找所有实例的成员;而 C
则需要在每个实例中使用一个字典。如果解释器非常聪明,它理论上可以发现所有 B
的实例都必须包含成员 name
和 hailstone_ending
,因此它可以把这看作和 A
是一样的。
但另一方面,如果允许在查找类成员的字典上使用 del
操作,那么这些类的查找机制可能是相同的,因为可用的成员会依赖于实例。
我感兴趣的是,我之前有一些代码创建了几千个 C
类型的类,我发现它运行得非常慢,而且占用内存很大。最近我用不同的方式重写了这段代码,感觉更高效了(但我还没有严格测试过,所以可能还是一样的)。
非常感谢你的见解!
2 个回答
在Python中,每个类和每个实例都有一个字典。A
使用的是类字典,而类B
和C
的例子则使用的是实例字典。B
和A
是不一样的——Python并不是为了速度而设计的,证明B
的实例不会被改变是非常困难,甚至几乎不可能。
证明:
>>> class D:
... def __init__(self):
... self.a = 3
...
>>> d = D()
>>> d.a
3
>>> D.a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: class D has no attribute 'a'
>>> dd = D()
>>> dd.a
3
>>> D.a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: class D has no attribute 'a'
你的问题让我想到了JavaScript的原型。
另外,如果在实例字典中找不到某个成员,查找时可以回退到类字典,但写入时会使用实例字典。
在底层,类的成员查找方式是一样的吗?
除非你重写了 __getattribute__
,否则属性查找的顺序是先检查对象的属性,然后再检查类的属性。它并不关心这个类是怎么来的。
看起来,A 只需要一个字典就能查找所有实例的成员;而 C 则需要在每个实例中使用一个字典。如果解释器足够聪明,它理论上可以注意到 B 的所有实例都必须包含成员 name 和 hailstone_ending,因此它可以和 A 等价。
在 A
中,属性存储在 A.__dict__
中,也就是在类本身上。而在 B
和 C
中,属性存储在 self.__dict__
中,也就是在实例上。这两个字典在所有情况下都是存在的。就这么简单。而且,B
和 C
之间没有区别。