如何创建简单的元类?

时间:2013-04-05 14:18:00

标签: python class factory metaclass

我一直在做Python已经有一段时间了,而且我总是在某种程度上理解元类的含义,但我从来不需要它。 现在我认为我的问题的最佳解决方案是元类(如果有更好的方法,请纠正我)。

我正在尝试创建的是一个系统,它会自动为我的每个类添加一个类变量n和一个列表instances。以下是一个类的简化示例:

class Foo:
    n = 0
    instances = []

    def __init__(self):
        self.index = Foo.n
        Foo.n += 1
        Foo.instances.append(self)

这个结构应该为我的7或8个类实现,我认为一个元类可能在这里帮助我。 我知道我可以使用Foo.__metaclass__ = MyMetaclass属性使用元类,但我如何创建元类?

2 个答案:

答案 0 :(得分:1)

实际上,在这里使用基类会更好:

class InstancesList(object): 
    def __new__(cls, *args, **kw):
        if not hasattr(cls, 'instances'):
            cls.instances = []
        return super(InstancesList, cls).__new__(cls, *args, **kw)

    def __init__(self):
        self.index = len(type(self).instances)
        type(self).instances.append(self)

class Foo(InstancesList):
    def __init__(self, arg1, arg2):
        super(Foo, self).__init__()
        # Foo-specific initialization

答案 1 :(得分:1)

请不要害怕学习如何使用元类。很少有人知道他们可以执行的魔术:

#!/usr/bin/env python3

def main():
    x = Foo()
    print('x.index:', x.index)
    print('x.n:', x.n)
    print('x.instances:', x.instances)
    print('x.instances[0] == x:', x.instances[0] == x)

class MyMetaClass(type):

    def __new__(cls, name, bases, namespace):
        namespace.setdefault('n', 0)
        namespace.setdefault('instances', [])
        namespace.setdefault('__new__', cls.__new)
        return super().__new__(cls, name, bases, namespace)

    @staticmethod
    def __new(cls, *args):
        instance = cls.__base__.__new__(cls)
        instance.index = cls.n
        cls.n += 1
        cls.instances.append(instance)
        return instance

class Foo(metaclass=MyMetaClass):

    def __init__(self):
        print('Foo instance created')

if __name__ == '__main__':
    main()