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

  • Post category:Python

Python 的类变量和实例变量是面向对象编程中的重要概念,但是也可能会造成一些陷阱。

类变量和实例变量的区别

类变量是在类定义时定义的,属于类本身,可以通过类名直接访问。所有实例共享同一个类变量。实例变量是在实例化类时定义的,每个实例拥有各自的实例变量。

示例代码:

“`python
class Sample:
class_var = 0 # 定义类变量

def __init__(self, instance_var):
    self.instance_var = instance_var # 定义实例变量

instance1 = Sample(1)
instance2 = Sample(2)

print(instance1.instance_var) # 打印实例变量,输出 1
print(instance2.instance_var) # 打印实例变量,输出 2

Sample.class_var = 1 # 修改类变量

print(instance1.class_var) # 打印类变量,输出 1
print(instance2.class_var) # 打印类变量,输出 1 注意到类变量的值同时被实例共享,修改类变量将影响所有实例。

类变量和实例变量的陷阱

当类变量值为可变对象(列表、字典等)时,共享类变量可能会造成意外的结果。

示例代码:

“`python
class BadExample:
class_var = []

def __init__(self, instance_var):
    self.instance_var = instance_var

instance1 = BadExample(1)
instance2 = BadExample(2)

instance1.class_var.append(1)

print(instance1.class_var) # 打印类变量,输出 [1]
print(instance2.class_var) # 打印类变量,输出 [1] 这是因为列表属于可变对象,在类定义时被创建出来,被所有实例所共享。当一个实例修改了该列表时,其他实例将看到相同的变化。因此,修改可变对象的类变量可能会对程序产生意外效果。

使用方法

为了避免变量混淆,推荐使用 self 来定义实例变量,使用类名或 cls 来定义类变量。对于可变对象的类变量,可以在类定义时使用深复制来避免共享。

示例代码:

“`python
import copy

class GoodExample:
class_var = []

def __init__(self, instance_var):
    self.instance_var = instance_var

@classmethod
def set_class_var(cls, value):
    cls.class_var = copy.deepcopy(value)

instance1 = GoodExample(1)
instance2 = GoodExample(2)

GoodExample.set_class_var([1])

print(instance1.class_var) # 打印类变量,输出 []
print(instance2.class_var) # 打印类变量,输出 [] 这样做使用了 @classmethod 装饰器来定义了一个类方法,该方法可以访问类变量,并使用深复制避免了共享可变对象。