问题
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