【问题标题】:how to override python metaclass method?如何覆盖python元类方法?
【发布时间】:2021-01-14 18:17:41
【问题描述】:

我几乎确信这是不可能的,但这里是: 我有一个类 a(enum.Enum) 我想覆盖从 metaclass=enum.EnumMeta 继承的 __contains__ 是否可以覆盖我的 a 类中的 EnumMeta::__contains__

我想我需要复制所有内容来实现这一点?

【问题讨论】:

  • 在某种程度上,然后再一次.. 我不想像建议的那样替换基类 Enum,这需要我复制 Enum 类的全部内容(不需要)。我找到了一种不同的方法,可以让我保持标准类的完整性,这样如果它们在未来发生变化,我仍然会得到这些变化,虽然它不是经典继承,但好处大于复杂性。

标签: python inheritance overriding metaclass


【解决方案1】:

您的解决方案将适用于您的特定枚举,但正如我在评论中指出的那样:它还将改变同一应用程序中 all 枚举的行为 - 包括在任何库深处使用的私有枚举(甚至是标准库中的枚举)。

遵循面向对象继承规则的“干净”方式是: 创建一个新的元类,继承自 Enum 的现有元类,并更新该类中的 __contains__ 方法。

然后创建一个新的Enum 基类,使用这个新的元类,但在其他方面与Enum 相同(只需用空主体编写即可):

import enum

class CustomEnumMeta(enum.EnumMeta):
    def __contains__(cls, element):
        # Mocking "contains"
        # It is usual to place "cls" instead of "self" in the metaclass
        # as the received "instance" will be a class in itself. 
        return True
    
class CustomEnum(Enum, metaclass=CustomEnumMeta):
    pass

class MyEnum(CustomEnum):
    a = 1
    b = 2
    

并在交互式提示中:

In [10]: "x" in MyEnum                                                                       
Out[10]: True

In [11]: MyEnum.a                                                                            
Out[11]: <MyEnum.a: 1>

如果您想在一些自定义逻辑之后推迟到正常的包含规则,在派生元类中,您可以在完成个性化规则后调用super().__contains__,例如:

...

def __contains__(cls, element):
    if member in cls._member_map_:
        return True
    return super().__contains__(cls, element)

它与你所做的只是有点不同,但它不会复制你自定义方法中 Enum 中原始 __contains__ 的逻辑。

【讨论】:

    【解决方案2】:

    所以我发现一种方式是这样的:

    def __mycontains__(cls, member):
        # this part is stolen from EnumMetas __contains__
        if isinstance(member, cls):
            return member._name_ in cls._member_map_
        if not isinstance(member, str):
            raise ValueError('Illegal enum name: {}'.format(member))
        return member in cls._member_map_
    
    class a(Enum):
       flaf = auto()
    
    setattr(a.__class__, __contains__, __mycontains__)
    

    这会根据需要更改执行if 'flaf' in a: 时调用的函数。 可能在某些情况下这种方法不是最好的,如果是这样,我很想听听 - 就我而言,我使用它来将解析的文本代码与枚举匹配,将事物桥接到键入的值而不是字符串。 ..

    【讨论】:

    • 是的 - 但这种方法会在你的应用程序的所有 Enum 中为 all __contains__ 设置一个新的 __contains__ 行为 - 甚至是在你不使用的库中存在的内部枚举'不知道,也可能在 in 操作中使用。
    • 当前标记为重复的问题中的答案也不合适,因为它没有考虑现有的 Enum 元类。
    猜你喜欢
    • 2022-09-30
    • 1970-01-01
    • 2020-07-02
    • 2012-09-27
    • 1970-01-01
    • 2023-03-15
    • 2011-03-05
    • 2020-11-17
    • 2014-03-17
    相关资源
    最近更新 更多