Stampa di tutte le istanze di una classe

Con una classe in Python, come faccio a definire una funzione per la stampa di ogni singola istanza della classe in un formato definito in funzione?

  • Che è un po ‘ confuso in questione. Vuoi un metodo funzione che formatta tutti allo stesso modo? O vuoi un insieme che contiene tutte le istanze?
  • Cercando di fare qualcosa con tutte le istanze di una classe è quasi sempre un errore, e un segno che non sei ancora utilizzato per organizzare i tuoi oggetti in strutture di dati. Con adeguate strutture di dati, il corretto funzionamento è qualcosa di simile a “fare [cosa] con tutti gli elementi di questa struttura di dati”, non “fare [cosa] con tutte le istanze di questa classe”.
InformationsquelleAutor user33061 | 2008-11-30

 

7 Replies
  1. 86

    Vedo due opzioni in questo caso:

    Garbage collector

    import gc
    for obj in gc.get_objects():
        if isinstance(obj, some_class):
            dome_something(obj)

    Questo ha lo svantaggio di essere molto lento quando si hanno un sacco di oggetti, ma funziona anche con i tipi delle quali non si ha alcun controllo.

    Utilizzare un mixin e weakrefs

    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

    In questo caso, tutti i riferimenti che vengono memorizzati come un riferimento debole in un elenco. Se si crea e si elimina un sacco di istanze di frequente, si dovrebbe pulire la lista di weakrefs dopo iterazione, altrimenti ci sarà un sacco di spazzatura.

    Un altro problema in questo caso è che è necessario assicurarsi di chiamare il costruttore della classe base. Si potrebbe anche ignorare __new__, ma solo il __new__ metodo di prima classe base viene utilizzato nella creazione di un’istanza. Questo funziona solo su tipi che sono sotto il vostro controllo.

    Modifica: Il metodo per la stampa di tutte le istanze in base a un formato specifico è lasciato come esercizio, ma è fondamentalmente solo una variazione sul for-loop.

    • +1 per il codice di campioni e demo per i deboli rif. Il garbage collector è interessante, ma probabilmente non è così utile per questo tipo di applicazione.
    • Lo so, ma è l’ultima risorsa se tutto il resto fallisce. Forse avrei dovuto metterlo come opzione 2.
    • IMO l’OP chiede di __str__() metodo.
    • Come estendere questo per includere i casi di bambini di classi?
    • Dato che Python 2.7 questo può essere fatto un po ‘ più semplice utilizzando un WeakSet.
    • Se ho due classi che ereditano entrambi da KeepRefs, quindi sembra che _refs è comune tra le due classi. Non è quello che volevo, e non mi rendevo conto di ereditarietà di classe avrebbe funzionato in questo modo. Significa che è necessario implementare KeepRefs come una metaclass in modo che ogni classe che utilizza ottiene il suo proprio _refs?
    • Molto bello e utile il codice, ma ha un grosso problema: la lista è sempre più grande e non è mai puliti, per provarlo basta aggiungere print(len(cls.__refs__[cls])) alla fine del get_instances metodo. ` @classmethod def get_instances(cls): cls.__rif__[cls] = [ instance_ref per instance_ref in cls.__rif__[cls] \ se instance_ref() non è Nessuno] per instance_ref in cls.__rif__[cls]: istanza = instance_ref() rendimento istanza di stampa(len(cls.__rif__[cls])) `

  2. 22

    Si desidera creare un elenco statico in classe, e aggiungere un weakref per ogni istanza in modo che il garbage collector può pulire le istanze che non sono più necessari.

    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)
  3. 6

    Molto bello e utile il codice, ma ha un grosso problema: elenco è sempre più grande e non è mai puliti, per provarlo basta aggiungere print(len(cls.__refs__[cls])) alla fine del get_instances metodo.

    Qui un fix per il get_instances metodo:

    __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

    o, in alternativa, potrebbe essere fatto utilizzando WeakSet:

    from weakref import WeakSet
    
    __refs__ = defaultdict(WeakSet)
    
    @classmethod
    def get_instances(cls):
        return cls.__refs__[cls]
  4. 3

    Come quasi tutti gli altri linguaggi OO, tenere tutte le istanze della classe in una raccolta di qualche tipo.

    Si può provare questo genere di cose.

    class MyClassFactory( object ):
        theWholeList= []
        def __call__( self, *args, **kw ):
             x= MyClass( *args, **kw )
             self.theWholeList.append( x )
             return x

    Ora si può fare questo.

    object= MyClassFactory( args, ... )
    print MyClassFactory.theWholeList
    • Non del tutto corretto. Alcuni linguaggi permettono di accedere al loro oggetto di memoria. In queste lingue, ad esempio, di Chiacchiere e di Ruby, la query di chiedere una classe per tutte le sue istanze. (In realtà, sono sorpreso di Python non offrono che come bene.)
    • Kuhn: vedi @NXC-post su Smalltalk è allInstances capacità. Forse Ruby è l’ultimo baluardo?
    • Personalmente preferisco non vedere l’interprete soffrono di overhead aggiuntivo, fornendo sempre qualcosa che non è sempre necessario, soprattutto quando il suo – come dimostrato – banalmente facile da attuare quando si tratta di.
  5. 3

    Python non hanno un equivalente Smallktalk di #allInstances come l’architettura non hanno questo tipo di oggetto centrale della tabella (anche se i moderni smalltalks non funzionano veramente come che sia).

    Come gli altri poster dice in modo esplicito la gestione di una collezione. La sua proposta di un metodo factory che mantiene un registro di sistema è perfettamente ragionevole per farlo. Si potrebbe desiderare di fare qualcosa con riferimenti deboli così non hai esplicitamente di tenere traccia di un oggetto di smaltimento.

  6. 1

    Non è chiaro se avete bisogno di stampare tutte le istanze della classe in una sola volta o quando sono inizializzati, né se si sta parlando di un classe si ha il controllo su vs di una classe in un 3rd party biblioteca.

    In ogni caso, vorrei risolvere questo scrivendo una classe di fabbrica utilizzando Python metaclass supporto. Se non hai il controllo sulla classe, aggiornare manualmente il __metaclass__ per la classe o modulo che si sta monitorando.

    Vedere http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html per ulteriori informazioni.

  7. 1

    Non hai bisogno di importare NULLA! Basta usare il “sé”. Ecco come fare questo

    class A:
        instances = []
        def __init__(self):
            self.__class__.instances.append(self)
    
        @classmethod
        def printInstances(cls):
            for instance in cls.instances:
                print(instance)
    A.printInstances()

    È così semplice. Nessun modulo o librerie importate

Lascia un commento