también puede resolver este problema utilizando una metaclass:
- Cuando una clase se crea (
__init__
método de metaclase), añadir un nuevo registro de la instancia
- Cuando se crea una nueva instancia de esta clase (
__call__
método de metaclase), añadirlo al registro de la instancia.
La ventaja de este enfoque es que cada clase tiene un registro, incluso si no existe una instancia. Por el contrario, al anular __new__
(como en Blckknght's answer), el registro se agrega cuando se crea la primera instancia.
class MetaInstanceRegistry(type):
"""Metaclass providing an instance registry"""
def __init__(cls, name, bases, attrs):
# Create class
super(MetaInstanceRegistry, cls).__init__(name, bases, attrs)
# Initialize fresh instance storage
cls._instances = weakref.WeakSet()
def __call__(cls, *args, **kwargs):
# Create instance (calls __init__ and __new__ methods)
inst = super(MetaInstanceRegistry, cls).__call__(*args, **kwargs)
# Store weak reference to instance. WeakSet will automatically remove
# references to objects that have been garbage collected
cls._instances.add(inst)
return inst
def _get_instances(cls, recursive=False):
"""Get all instances of this class in the registry. If recursive=True
search subclasses recursively"""
instances = list(cls._instances)
if recursive:
for Child in cls.__subclasses__():
instances += Child._get_instances(recursive=recursive)
# Remove duplicates from multiple inheritance.
return list(set(instances))
Uso: Cree un registro y la subclase.
class Registry(object):
__metaclass__ = MetaInstanceRegistry
class Base(Registry):
def __init__(self, x):
self.x = x
class A(Base):
pass
class B(Base):
pass
class C(B):
pass
a = A(x=1)
a2 = A(2)
b = B(x=3)
c = C(4)
for cls in [Base, A, B, C]:
print cls.__name__
print cls._get_instances()
print cls._get_instances(recursive=True)
print
del c
print C._get_instances()
Si el uso de clases base abstractas del módulo abc
, simplemente subclase abc.ABCMeta
para evitar MetaClass conflictos:
from abc import ABCMeta, abstractmethod
class ABCMetaInstanceRegistry(MetaInstanceRegistry, ABCMeta):
pass
class ABCRegistry(object):
__metaclass__ = ABCMetaInstanceRegistry
class ABCBase(ABCRegistry):
__metaclass__ = ABCMeta
@abstractmethod
def f(self):
pass
class E(ABCBase):
def __init__(self, x):
self.x = x
def f(self):
return self.x
e = E(x=5)
print E._get_instances()
Sospecho que no es posible sin una profunda introspección (por ejemplo, de forma recursiva la expansión de todos los objetos en los 'locales 'y diccionarios 'globales' de todos sus marcos de pila). Es mucho más fácil hacer que el método '__init__' o' __new__' de su clase cree una referencia débil y la pegue en una lista en alguna parte. – Blckknght
Esta pregunta lo explica: http://stackoverflow.com/questions/328851/python-printing-all-instances-of-a-class – TJD
@Blckknght: involuntariamente robé su sugerencia por mi respuesta. –