能否为自定义Python Enum传递关键字参数(kwargs)?
自定义Python Enum成员的关键字参数疑惑
问题背景
我们可以自定义Python Enum让成员拥有额外属性,常见写法如下:
class EnumWithAttrs(Enum): def __new__(cls, *args, **kwargs): value = len(cls.__members__) + 1 obj = object.__new__(cls) obj._value_ = value return obj def __init__(self, a, b): self.a = a self.b = b GREEN = 'a', 'b' BLUE = 'c', 'd'
多数示例中__new__方法声明接收**kwargs,但尝试通过类定义或函数式语法传递关键字参数时均触发语法错误:
类定义写法报错:
class EnumWithAttrs(Enum): GREEN = 'a', foo='b' BLUE = 'c', **{'bar': 'd'}
函数式写法也报错:
Color = EnumWithAttrs('Color', [('GREEN', 'a', foo='b'), ('BLUE', 'c', **{'bar': 'd'})])
请问开发者在__new__中声明**kwargs是出于习惯,还是存在合法使用方式?注:不接受将字典作为位置参数的替代方案。
解答
1. 常规写法无法传递关键字参数的原因
Python语法规则和Enum底层逻辑共同限制了参数传递方式:
- 类定义中,
GREEN = 'a', foo='b'属于非法表达式,逗号分隔的赋值右侧不能混合位置值和关键字参数语法。 - 函数式创建Enum时,
('GREEN', 'a', foo='b')同样违反元组语法,元组元素只能是具体值,不能包含关键字参数声明。
Enum底层只会将成员赋值右侧的内容拆解为位置参数传递给__new__和__init__,没有处理关键字参数的入口。
2. __new__中声明**kwargs的主要原因
多数情况是编程习惯延续:
- 防御性编程:开发者为兼容未来Enum底层可能的功能变化(比如官方新增关键字参数支持),提前预留参数位,避免后续大规模修改代码。
- 通用构造方法模仿:很多类的
__new__或__init__会添加**kwargs来接收未明确声明的额外参数,防止意外传入参数导致报错,这种写法被自然延续到了Enum自定义场景中。
3. 合法使用**kwargs的特殊场景
如果绕过常规Enum成员定义语法,通过手动创建并注册成员的方式,可以合法传递关键字参数。示例如下:
from enum import Enum class EnumWithAttrs(Enum): def __new__(cls, *args, **kwargs): value = len(cls.__members__) + 1 obj = object.__new__(cls) obj._value_ = value # 处理传入的关键字参数 for key, val in kwargs.items(): setattr(obj, key, val) return obj def __init__(self, a): self.a = a # 手动创建成员并完成初始化 green_member = EnumWithAttrs.__new__(EnumWithAttrs, 'a', foo='b') green_member.__init__('a') # 将成员注册到Enum的成员映射字典中 EnumWithAttrs._member_map_['GREEN'] = green_member
这种方式避开了常规语法限制,能合法利用__new__中的**kwargs,但需要手动处理成员注册逻辑,仅适合特殊场景,不推荐作为常规写法。
内容的提问来源于stack exchange,提问作者mahkitah
相关产品推荐
相关产品推荐

