在许多情况下(包括我在下面这个问题中使用的示例),与使用元类相比,覆盖
__init_subclass__()
是一种更直接的解决方案。在所有其他情况下,下面的Martijn Pieters 的答案效果很好。
在 Python 3.2 或更高版本中是否有一种方法可以定义一个类,其子类应该使用特定的元类创建,而不需要使用该元类创建类本身?
一个演示我的意思的例子:假设我想创建一个
Enum
类,其子类可用于定义枚举类型。枚举类型将具有固定数量的实例,每个实例都有不同的 int
(或其他)值。枚举类型可以通过创建 Enum
的子类并将值分配给该类的属性来声明。通过 Enum
的元类,这些属性的值将被新类的实例替换。
Enum
类还可以定义一些可在其子类或其实例上使用的类或实例方法或成员。
class EnumMeta(type):
def __new__(mcs, what, bases, dict):
cls = super().__new__(mcs, what, bases, { })
cls._instances_by_value = { }
for k, v in dict.items():
if k.startswith('__') or k == 'get_by_value':
setattr(cls, k, v)
else:
instance = cls(k, v)
setattr(cls, k, instance)
cls._instances_by_value[v] = instance
return cls
class Enum(metaclass = EnumMeta):
def __init__(self, name, value):
self.name = name
self.value = value
def __repr__(self):
return '{}.{}'.format(type(self).__name__, self.name)
@classmethod
def get_by_value(cls, value):
return cls._instances_by_value[value]
创建此类枚举类型的示例:
class Boolean(Enum):
true = 0
false = 1
file_not_found = 2
print(Boolean.true) # Prints Boolean.true
print(Boolean.get_by_value(1)) # Prints Boolean.false
在
EnumMeta.__new__
的定义中,您可以看到我必须将 get_by_value
从元类的处理中排除。当我想使用元类以某种方式处理类定义的成员时,我经常遇到这个问题。
在对基类的所有子类使用元类时,将基类(示例中的
Enum
)排除在元类(示例中的EnumMeta
)处理之外的首选方法是什么?
我不认为在处理子类的成员时排除基类的所有成员是首选方法。我不关心
type(Enum)
的价值。它可以是 EnumMeta
或 type
。
你的“父”
Enum
不会有任何基数,只有从Enum
派生的类才会有一个非空的bases
元组。使用它可以轻松地尽早退出并通过常规 __new__
调用创建基类:
class EnumMeta(type):
def __new__(mcs, what, bases, dict):
if not bases:
# Enum itself
return super().__new__(mcs, what, bases, dict)
# Process subclass creation