¿Cómo creo una metaclase simple?

He estado haciendo Python por algún tiempo, y siempre he entendido un poco el significado de las metaclases, pero nunca he necesitado una. Ahora creo que la mejor solución para mi problema es una metaclase (corríjame si hay una mejor manera).

Lo que estoy tratando de crear es un sistema que automáticamente agrega una variable de clase n y una lista de instances a cada clase mía. Aquí hay un ejemplo simplificado de una clase:

 class Foo: n = 0 instances = [] def __init__(self): self.index = Foo.n Foo.n += 1 Foo.instances.append(self) 

Esta estructura debería implementarse para 7 u 8 clases mías, y estaba pensando que una metaclase podría ayudarme aquí. Sé que puedo usar el atributo Foo.__metaclass__ = MyMetaclass para usar la metaclase, pero ¿cómo creo la metaclase?

En realidad, usar una clase base funcionaría mejor aquí:

 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 

Por favor, no tenga miedo de aprender a usar metaclases. Pocas personas saben la magia que pueden realizar:

 #!/usr/bin/env python3 def main(): x = Foo() print('x.index:', x.index) print('xn:', xn) 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()