如何在Python中创建无元类冲突的FractionEnum?
实现FractionEnum的踩坑与解决过程
1. 初始尝试:元类冲突
尝试创建类似StrEnum/IntEnum的FractionEnum,直接继承fractions.Fraction和Enum:
class FractionEnum(fractions.Fraction, Enum): VALUE_1 = 1, 1 VALUE_2 = 8, 9
运行后触发元类冲突错误:
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
2. 解决元类冲突,但触发新错误
自定义元类解决冲突问题:
class FractionEnumMeta(type(Enum), type(fractions.Fraction)): pass class FractionEnum(fractions.Fraction, Enum, metaclass=FractionEnumMeta): VALUE_1 = 1, 1 VALUE_2 = 8, 9
元类冲突解决后,又出现新的类型错误:
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/enum.py", line 289, in __new__ enum_member = __new__(enum_class, *args) File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/fractions.py", line 93, in __new__ self = super(Fraction, cls).__new__(cls) TypeError: Enum.__new__() missing 1 required positional argument: 'value'
问题根源在于Fraction的__new__方法调用父类构造时,错误触发了Enum的构造逻辑——Enum的__new__需要必填的value参数,两者构造流程不兼容(不像int/str可以直接与Enum混合实现)。
3. 替换__new__后,深拷贝触发枚举扩展错误
替换Fraction的__new__方法后,枚举可以正常工作,但深拷贝包含该枚举成员的对象时,再次报错:
/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/enum.py:497: in _create_ _, first_enum = cls._get_mixins_(cls, bases)
具体错误内容:
# ensure final parent class is an Enum derivative, find any concrete # data type, and check that Enum has no members first_enum = bases[-1] if not issubclass(first_enum, Enum): raise TypeError("new enumerations should be created as " "`EnumName([mixin_type, ...] [data_type,] enum_type)`") member_type = _find_data_type(bases) or object if first_enum._member_names_: > raise TypeError("Cannot extend enumerations") E TypeError: Cannot extend enumerations
复现代码:
class TestFractionEnum(FractionEnum): VALUE_1 = 1, 1 VALUE_2 = 8, 9 class C: def __init__(self): self.fraction_enum = TestFractionEnum.VALUE_1 c = C() print(c) print(c.fraction_enum) d = copy.copy(c) print(d) e = copy.deepcopy(c) print(e)
4. 最终解决:重写__deepcopy__方法
给FractionEnum添加自定义的__deepcopy__方法,绕过深拷贝时的枚举构造逻辑,直接返回已存在的枚举成员,问题得以解决:
def __deepcopy__(self, memo): if type(self) == Fraction: return self for item in self.__class__: if self == item: return item assert f'Invalid enum: {self}'
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

