How do I create a simple metaclass?

与世无争的帅哥 提交于 2019-11-30 18:49:55

问题


I've been doing Python for some time now, and I've always somewhat understood the meaning of metaclasses, but I've never needed one. Now I think the best solution for my problem is a metaclass (correct me if there's a better way).

What I'm trying to create is a system which automatically adds a class variable n and a list instances to each class of mine. Here's a simplified example of one class:

class Foo:
    n = 0
    instances = []

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

This structure should be implemented for 7 or 8 classes of mine, and I was thinking that a metaclass might help me here. I know I can use the Foo.__metaclass__ = MyMetaclass attribute to use the metaclass, but how do I create the metaclass?


回答1:


Actually, using a base class would work out better here:

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



回答2:


Please, do not be afraid to learn how to use metaclasses. Few people know the magic they can perform:

#!/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()


来源:https://stackoverflow.com/questions/15836263/how-do-i-create-a-simple-metaclass

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!