如何覆盖 python 元类方法?

how to override python metaclass method?

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

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

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

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: 时调用的函数。 可能在某些情况下这种方法不是最好的,如果是这样,我很想听听它 - 就我而言,我使用它来将解析的文本代码与枚举相匹配,将事物桥接到键入的值而不是字符串。 ..

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

遵循面向对象继承规则的“干净”方法是: 为 Enum 创建一个新的元class,继承现有的元class,并更新此 class.

中的 __contains__ 方法

然后创建一个新的Enum基础,使用这个新的metaclass,但在其他方面与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>

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

...

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

只是和你做的有点不同,但它并没有重复你自定义方法中 Enum 中原始 __contains__ 的逻辑。