如何覆盖 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__
的逻辑。
我几乎确信这是不可能的,但这里是:
我有 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__
的逻辑。