Python多属性Enum技术疑问:Pylance报错与简化实例化
关于Python多属性Enum的两个问题解答
先贴出原代码:
from enum import Enum class MultiAttr(Enum): RED = (1, 10) GREEN = (2, 20) BLUE = (3, 20) def __init__(self, id, val): self.id = id self.val = val assert MultiAttr((2, 20)) == MultiAttr.GREEN # 断言正常通过
问题1:VSCode的Pylance为什么提示“Argument missing for parameter "val"”?
这是Pylance静态类型检查的误报。原因如下:
- Enum类有特殊逻辑:定义成员时赋值的元组(比如
GREEN=(2,20)),会在初始化成员时自动拆包成__init__的参数(即把2传给id,20传给val)。 - 但Pylance的类型检查器只识别
__init__的签名(需要id和val两个参数),没适配Enum自动拆包成员值元组的特性,所以看到你写MultiAttr((2,20))时,误以为只传了一个参数给需要两个参数的构造逻辑,从而报错。 - 实际上这段代码运行完全正常,只是静态检查没覆盖Enum的这个特殊行为。
问题2:能不能实现MultiAttr(2) == MultiAttr.GREEN的实例化方式?
可以,通过重写Enum的__call__方法即可实现,同时还能保留原来按元组查找的用法。修改后的代码如下:
from enum import Enum class MultiAttr(Enum): RED = (1, 10) GREEN = (2, 20) BLUE = (3, 20) def __init__(self, id, val): self.id = id self.val = val @classmethod def __call__(cls, value, *args, **kwargs): # 先尝试按原始元组值查找,兼容原有用法 try: return super().__call__(value, *args, **kwargs) except ValueError: # 按元组查找失败时,遍历成员匹配id for member in cls: if member.id == value: return member # 都找不到则抛出标准错误 raise ValueError(f"{value} is not a valid {cls.__name__}") assert MultiAttr(2) == MultiAttr.GREEN # 该断言现在可正常通过 assert MultiAttr((2,20)) == MultiAttr.GREEN # 原有用法不受影响
原理是重写__call__方法,先调用父类的默认逻辑处理原始查找方式;如果传入的是单个id导致查找失败,就遍历所有成员,找到id匹配的返回。
内容的提问来源于stack exchange,提问作者Philippe
相关产品推荐
相关产品推荐

