You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python抽象Enum/枚举层级构建:库与消费项目实例化问题

枚举继承实例化问题的简洁解决方案

问题背景

我有一个库项目和多个消费项目,消费项目会调用库的核心功能。库中定义了AbstractProgrammCode枚举作为父类,消费项目需要通过添加枚举值来实现具体的枚举类(比如ProgrammCode)。现在遇到的问题是:库中的通用创建方法无法实例化消费项目里的具体枚举,报错提示440不是AbstractProgrammCode的成员——我知道是因为枚举继承机制没被正确识别,想找最简洁的解决办法。

现有代码示例

库项目中的父枚举

import logging
from enum import Enum

class AbstractProgrammCode(Enum):

    @staticmethod
    def create_with(string: str):
        if not string or not string.strip().isnumeric():
            raise ValueError("'" + str(string) + "' is not a valid Programm Code. Expected: eg. '440'.") 

        result = AbstractProgrammCode(int(string.strip()))
        logging.getLogger(__name__).debug("ProgrammCode '" + str(result.name) + "' created.")
        return result

消费项目中的具体枚举

from lib.abstract_programm_code import AbstractProgrammCode

class ProgrammCode(AbstractProgrammCode):
    P440 = 440
    P431 = 431
    P441 = 441
    P455 = 455

调用代码与报错

调用代码:

code = ProgrammCode.create_with(str(440))

报错栈:

tests/re_v1/decision/decider_test.py:100: in __create_dto
    code = ProgrammCode.create_with(str(programm_nr))
__app__/re_v1/programm/abstract_programm_code.py:11: in create_with
    result = AbstractProgrammCode(int(string.strip()))
/usr/lib/python3.9/enum.py:360: in __call__
    return cls.__new__(cls, value)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

cls = <enum 'AbstractProgrammCode'>, value = 440

    def __new__(cls, value):
        # all enum instances are actually created during class construction
        # without calling this method; this method is called by the metaclass'
        # __call__ (i.e. Color(3) ), and by pickle
        if type(value) is cls:
            # For lookups like Color(Color.RED)
            return value
        # by-value search for a matching enum member
        # see if it's in the reverse mapping (for hashable values)
        try:
            return cls._value2member_map_[value]
        except KeyError:
            # Not found, no need to do long O(n) search
            pass
        except TypeError:
            # not there, now do long search -- O(n) behavior
            for member in cls._member_map_.values():
                if member._value_ == value:
                    return member
        # still not found -- try _missing_ hook
        try:
            exc = None
            result = cls._missing_(value)
        except Exception as e:
            exc = e
            result = None
        try:
            if isinstance(result, cls):
                return result
            else:
                ve_exc = ValueError("%r is not a valid %s" % (value, cls.__qualname__))
                if result is None and exc is None:
>                   raise ve_exc
E                   ValueError: 440 is not a valid AbstractProgrammCode

/usr/lib/python3.9/enum.py:678: ValueError

解决方案

问题根源在于create_with是静态方法,里面硬编码实例了父类AbstractProgrammCode,完全没用到调用这个方法的子类(比如ProgrammCode)。把静态方法改成类方法就能解决:

修改后的库枚举代码:

import logging
from enum import Enum

class AbstractProgrammCode(Enum):

    @classmethod
    def create_with(cls, string: str):
        if not string or not string.strip().isnumeric():
            raise ValueError(f"'{string}' is not a valid Programm Code. Expected: eg. '440'.") 

        result = cls(int(string.strip()))  # 用cls代替硬编码的AbstractProgrammCode
        logging.getLogger(__name__).debug(f"ProgrammCode '{result.name}' created.")
        return result

改动说明

  1. 把@staticmethod换成@classmethod,方法参数添加cls——这个cls代表当前调用方法的类(子类ProgrammCode调用时,cls就是ProgrammCode)
  2. 实例枚举时用cls(int(string.strip()))代替AbstractProgrammCode(...),这样就会去实例子类而非父类
  3. 顺便把字符串拼接改成f-string,代码更简洁

改完之后再调用ProgrammCode.create_with(str(440)),就能正常返回ProgrammCode.P440了。

内容的提问来源于stack exchange,提问作者Kai B.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 07:00:35