web-dev-qa-db-fra.com

Impression de toutes les instances d'une classe

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?

53
user33061

Je vois deux options dans ce cas:

Éboueur

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.

Utilisez un mixin et des références faibles

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-.

86
Torsten Marek

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)
22
MirkoT

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]
6
Fabio Caccamo

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
3
S.Lott

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.

1
Daniel Naab

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é

1