Avec une classe en Python, comment définir une fonction pour imprimer chaque instance unique de la classe dans un format défini dans la fonction?
Je vois deux options dans ce cas:
import gc
for obj in gc.get_objects():
if isinstance(obj, some_class):
dome_something(obj)
Cela a l'inconvénient d'être très lent lorsque vous avez beaucoup d'objets, mais fonctionne avec des types sur lesquels vous n'avez aucun contrôle.
from collections import defaultdict
import weakref
class KeepRefs(object):
__refs__ = defaultdict(list)
def __init__(self):
self.__refs__[self.__class__].append(weakref.ref(self))
@classmethod
def get_instances(cls):
for inst_ref in cls.__refs__[cls]:
inst = inst_ref()
if inst is not None:
yield inst
class X(KeepRefs):
def __init__(self, name):
super(X, self).__init__()
self.name = name
x = X("x")
y = X("y")
for r in X.get_instances():
print r.name
del y
for r in X.get_instances():
print r.name
Dans ce cas, toutes les références sont stockées en tant que référence faible dans une liste. Si vous créez et supprimez un grand nombre d'instances fréquemment, vous devez nettoyer la liste des références faibles après l'itération, sinon il y aura beaucoup de corruption.
Un autre problème dans ce cas est que vous devez vous assurer d'appeler le constructeur de la classe de base. Vous pouvez également remplacer __new__
, mais seulement le __new__
La méthode de la première classe de base est utilisée lors de l'instanciation. Cela ne fonctionne également que sur les types sous votre contrôle.
Edit: La méthode pour imprimer toutes les instances selon un format spécifique est laissée comme un exercice, mais c'est fondamentalement juste une variation sur les boucles for
-.
Vous souhaiterez créer une liste statique sur votre classe et ajouter un weakref
à chaque instance afin que le garbage collector puisse nettoyer vos instances lorsqu'elles ne sont plus nécessaires.
import weakref
class A:
instances = []
def __init__(self, name=None):
self.__class__.instances.append(weakref.proxy(self))
self.name = name
a1 = A('a1')
a2 = A('a2')
a3 = A('a3')
a4 = A('a4')
for instance in A.instances:
print(instance.name)
Code très agréable et utile, mais il a un gros problème: la liste est toujours plus grande et il n'est jamais nettoyé, pour le tester il suffit d'ajouter print(len(cls.__refs__[cls]))
à la fin du get_instances
méthode.
Voici un correctif pour le get_instances
méthode:
__refs__ = defaultdict(list)
@classmethod
def get_instances(cls):
refs = []
for ref in cls.__refs__[cls]:
instance = ref()
if instance is not None:
refs.append(ref)
yield instance
# print(len(refs))
cls.__refs__[cls] = refs
ou bien cela pourrait être fait en utilisant WeakSet:
from weakref import WeakSet
__refs__ = defaultdict(WeakSet)
@classmethod
def get_instances(cls):
return cls.__refs__[cls]
Identique à presque toutes les autres langues OO, conservez toutes les instances de la classe dans une collection quelconque).
Vous pouvez essayer ce genre de chose.
class MyClassFactory( object ):
theWholeList= []
def __call__( self, *args, **kw ):
x= MyClass( *args, **kw )
self.theWholeList.append( x )
return x
Vous pouvez maintenant le faire.
object= MyClassFactory( args, ... )
print MyClassFactory.theWholeList
Python n'a pas d'équivalent à #allInstances de Smallktalk, car l'architecture n'a pas ce type de table d'objets centrale (bien que les petites entreprises modernes ne fonctionnent pas vraiment comme ça non plus).
Comme le dit l'autre affiche, vous devez gérer explicitement une collection. Sa suggestion d'une méthode d'usine qui maintient un registre est une façon parfaitement raisonnable de le faire. Vous voudrez peut-être faire quelque chose avec références faibles afin que vous n'ayez pas à garder explicitement la trace de l'élimination des objets.
Il n'est pas clair si vous devez imprimer toutes les instances de classe en même temps ou quand elles sont initialisées, ni si vous parlez d'une classe que vous contrôlez par rapport à une classe dans une bibliothèque tierce.
Dans tous les cas, je résoudrais cela en écrivant une fabrique de classe en utilisant Python. Si vous n'avez pas le contrôle sur la classe, mettez à jour manuellement le __metaclass__
pour la classe ou le module que vous suivez.
Voir http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html pour plus d'informations.
Vous n'avez besoin d'importer RIEN! Utilisez simplement "self". Voici comment procéder
class A:
instances = []
def __init__(self):
self.__class__.instances.append(self)
@classmethod
def printInstances(cls):
for instance in cls.instances:
print(instance)
A.printInstances()
C'est aussi simple que ça. Aucun module ou bibliothèque importé