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 装饰器来定义了一个类方法,该方法可以访问类变量,并使用深复制避免了共享可变对象。