仅为子类使用元类

时间:2014-01-20 10:18:22

标签: python python-3.x metaclass

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)的价值。它可以是EnumMetatype

1 个答案:

答案 0 :(得分:7)

您的“父级”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