详解Python 类变量与实例变量的陷阱

  • Post category:Python

Python的类变量和实例变量都是对象的属性,但它们的作用范围是不同的。类变量是所有实例共享的,而实例变量只属于各自的实例。

类变量

类变量被定义在类的内部,但在实例方法之外。可以通过类名和实例名访问类变量。在创建实例时,如果实例没有该变量的实例变量,则会继承类变量的值。

class MyClass:
    class_var = 1   # 类变量

print(MyClass.class_var)    # 1

mc = MyClass()
print(mc.class_var)    # 1

但是,当你修改实例的类变量时,实例的类变量将被创建并覆盖类变量,而不影响其他实例或类。

class MyClass:
    class_var = 1    # 类变量

mc1 = MyClass()
mc2 = MyClass()

mc1.class_var = 2    # 创建实例变量并覆盖类变量
print(mc1.class_var)   # 2

print(mc2.class_var)   # 1, 确认类变量没有被修改
print(MyClass.class_var)   # 1, 确认类变量没有被修改

因此,当您需要在所有实例之间共享数据时,请使用类变量。但是,如果您想在实例之间维护实例特定的数据,请使用实例变量。

实例变量

实例变量是每个实例特有的变量,只能在实例方法内定义。

class MyClass:
    def __init__(self, arg):
        self.instance_var = arg    # 实例变量

mc1 = MyClass('foo')
print(mc1.instance_var)    # 'foo'

mc2 = MyClass('bar')
print(mc2.instance_var)    # 'bar'

如果您需要将数组或对象分配给实例变量,则需要小心。因为实例变量实际上保存了引用,而不是对象的副本。当一个实例变量在一个实例中被改变时,该实例变量中的数据也将更改。如果有多个实例共享相同的数据,一个实例的更改将影响所有实例。

class MyClass:
    instance_list = []    # 实例变量,会和所有实例共享

    def __init__(self, arg):
        self.instance_list.append(arg)

mc1 = MyClass('foo')
mc2 = MyClass('bar')

print(mc1.instance_list)   # ['foo', 'bar']
print(mc2.instance_list)   # ['foo', 'bar']

如果要避免这种情况,需要调用构造函数时重新创建实例变量。

class MyClass:
    def __init__(self, arg):
        self.instance_list = []   # 创建一个新的实例变量
        self.instance_list.append(arg)

mc1 = MyClass('foo')
mc2 = MyClass('bar')

print(mc1.instance_list)    # ['foo']
print(mc2.instance_list)    # ['bar']

所以,在使用类变量和实例变量时,您需要小心。如果用途不当,可能会造成不必要的麻烦。