Python中__class_getitem__引发类属性可变的问题咨询
问题根源与解决方案
核心问题
你在__class_getitem__里直接修改了类本身的属性(sub_type和max_len),类属性是所有该类的实例、甚至类本身共享的全局值。每次调用List[xxx, xxx]都会覆盖这些属性,所以不管你返回类还是实例,后续访问都会拿到最后一次修改的结果。
为什么返回实例也没用
当你返回cls()时,如果你没有给实例单独设置sub_type和max_len属性,访问实例的这两个属性时,Python会自动去类上查找对应的类属性——而类属性已经被最后一次调用的List[Int,10]修改了,所以所有实例都会用最新的类属性值。
正确实现方式
方式1:动态创建子类(适合作为类型标记)
每次调用List[xxx, xxx]时,创建一个继承自原List的子类,子类拥有自己独立的类属性,不会互相干扰:
def __class_getitem__(cls, parameters): if not isinstance(parameters, tuple): parameters = (parameters,) if len(parameters) > 2: raise TypeError("Expected 2 arguments: List[sub_type, max_length]") sub_type = parameters[0] if len(parameters) >= 1 else None max_len = parameters[1] if len(parameters) >= 2 else None if max_len is not None and max_len <= 0: raise TypeError(f"Max Length of {max_len} is less than or equal to 0") # 动态生成唯一子类,每个子类有独立的类属性 subclass_name = f"{cls.__name__}[{sub_type.__name__}, {max_len}]" return type(subclass_name, (cls,), {"sub_type": sub_type, "max_len": max_len})
方式2:返回带实例属性的对象(适合直接使用)
不修改类属性,而是给创建的实例单独设置属性,每个实例的属性独立:
def __class_getitem__(cls, parameters): if not isinstance(parameters, tuple): parameters = (parameters,) if len(parameters) > 2: raise TypeError("Expected 2 arguments: List[sub_type, max_length]") sub_type = parameters[0] if len(parameters) >= 1 else None max_len = parameters[1] if len(parameters) >= 2 else None if max_len is not None and max_len <= 0: raise TypeError(f"Max Length of {max_len} is less than or equal to 0") # 创建实例并设置独立的实例属性 instance = cls() instance.sub_type = sub_type instance.max_len = max_len return instance
补充说明
- 方式1常用于类型注解场景(比如PEP 484的泛型类型),每个
List[Int,10]是不同的类类型。 - 方式2适合直接创建可使用的对象,每个实例的属性互不影响。
内容的提问来源于stack exchange,提问作者dvr
相关产品推荐
相关产品推荐

