Python类静态成员的‘半静态’行为机制解析
Python类共享成员的行为解析与猜想验证
先看你给出的测试代码:
class Test: x = 0 y = 'ok' z = [1, 2, 3] t1 = Test() t2 = Test()
猜想验证
猜想1:不可变类型初始指向同一实例,赋值时指向不同地址
正确。int、str这类不可变类型的对象一旦创建就无法修改内容。初始时t1.x和t2.x都没有自己的实例属性,会去类Test的属性里查找,所以指向同一个0对象。当执行t1.x = 5时,是给t1实例新增了一个名为x的属性,指向新创建的5对象;同理t2.x =7是给t2新增属性指向7,此时两个实例的x就指向不同内存地址了。
猜想2:Python没有真正的静态成员,Test.x是遍历重分配所有实例x的语法糖
错误。Python不存在所谓的“遍历重分配实例属性”的逻辑。Test.x是类的属性,存储在类对象的__dict__中。当实例没有自己的同名属性时,会沿着继承链向上查找类的属性;当你修改Test.x时,只是修改了类对象的属性值,后续实例查找x时(只要实例自己没定义x)就会拿到新的值,根本不会去修改实例的属性。
猜想3:Test.z未被重分配,仅调用方法修改,所以影响所有实例
部分正确,但表述不准确。Test.z += [4]本质是调用列表的__iadd__方法,属于原地修改列表对象的内容,并没有给Test.z重新赋值新的列表对象。而t1.z += [5]时,因为t1没有自己的z属性,所以会先找到类的z对象,然后调用它的__iadd__方法原地修改,所有共享这个列表的实例(包括t2和Test本身)都会看到修改后的结果。如果是执行t1.z = [1,2],那就是给t1新增了自己的z属性,之后t1.z就和类的z无关了。
Python类成员的实际机制
Python里没有传统意义上的“静态成员”,类中定义的属性是类属性,属于类对象本身:
- 属性查找顺序:当你访问
instance.attr时,Python会先在实例自己的__dict__(实例属性字典)里找attr;如果找不到,就去实例所属类的__dict__里找;再找不到就去父类的__dict__里找,直到找到或者抛出AttributeError。 - 不可变类属性与实例属性的分离:当你给实例赋值
instance.attr = value时,不管类里有没有同名的attr,都会在实例的__dict__里新增这个属性,之后访问instance.attr就会优先用实例自己的属性,和类属性彻底分离。这就是为什么修改不可变类属性后,实例能看到变化,但给实例赋值后就独立了。 - 可变类属性的共享特性:对于列表、字典这类可变对象,类属性存储的是对象的引用。当你通过实例或类调用可变对象的原地修改方法(比如
list.append、dict.update)时,修改的是同一个对象的内容,所有共享这个引用的实例和类都会看到变化。只有当你给实例赋值新的可变对象时,才会让实例拥有独立的属性。
内容的提问来源于stack exchange,提问作者Rares Dima
相关产品推荐
相关产品推荐

