Domanda

Voglio controllare regolarmente se un oggetto ha un membro o meno. Un esempio è la creazione di un singleton in una funzione. A tale scopo, puoi utilizzare hasattr in questo modo:

class Foo(object):
    @classmethod
    def singleton(self):
        if not hasattr(self, 'instance'):
            self.instance = Foo()
        return self.instance

Ma puoi anche farlo:

class Foo(object):
    @classmethod
    def singleton(self):
        try:
            return self.instance
        except AttributeError:
            self.instance = Foo()
            return self.instance

Un metodo è migliore dell'altro?

Modifica: Aggiunto il @classmethod ... Ma nota che la domanda non è non su come creare un singleton ma come controllare la presenza di un membro in un oggetto.

Modifica: Per quell'esempio, un uso tipico sarebbe:

s = Foo.singleton()

Quindi s è un oggetto di tipo Foo , lo stesso ogni volta. E, in genere, il metodo viene chiamato molte volte.

È stato utile?

Soluzione

Queste sono due diverse metodologie: & # 8470; 1 è LBYL (prima di saltare) e & # 8470; 2 è EAFP (più facile chiedere perdono che autorizzazione).

I pitonisti suggeriscono in genere che EAFP è migliore, con argomenti nello stile di " che cosa succede se un processo crea il file tra il tempo in cui lo provi e il momento in cui provi a crearlo tu stesso? " ;. Questo argomento non si applica qui, ma è l'idea generale. Le eccezioni non dovrebbero essere considerate troppo eccezionali.

Dal punto di vista delle prestazioni nel tuo caso & # 8212; poiché l'impostazione dei gestori di eccezioni (la parola chiave try ) è molto economica in CPython durante la creazione di un'eccezione (la parola chiave raise e la creazione di eccezioni interne) è ciò che è relativamente costoso & # 8212; usando il metodo & # 8470; 2 l'eccezione verrebbe sollevata una sola volta; successivamente, basta usare la proprietà.

Altri suggerimenti

Ho appena provato a misurare i tempi:

class Foo(object):
    @classmethod
    def singleton(self):
        if not hasattr(self, 'instance'):
            self.instance = Foo()
        return self.instance



class Bar(object):
    @classmethod
    def singleton(self):
        try:
            return self.instance
        except AttributeError:
            self.instance = Bar()
            return self.instance



from time import time

n = 1000000
foo = [Foo() for i in xrange(0,n)]
bar = [Bar() for i in xrange(0,n)]

print "Objs created."
print


for times in xrange(1,4):
    t = time()
    for d in foo: d.singleton()
    print "#%d Foo pass in %f" % (times, time()-t)

    t = time()
    for d in bar: d.singleton()
    print "#%d Bar pass in %f" % (times, time()-t)

    print

Sul mio computer:

Objs created.

#1 Foo pass in 1.719000
#1 Bar pass in 1.140000

#2 Foo pass in 1.750000
#2 Bar pass in 1.187000

#3 Foo pass in 1.797000
#3 Bar pass in 1.203000

Sembra che provare / tranne sia più veloce. Mi sembra anche più leggibile, dipende comunque dal caso, questo test è stato molto semplice forse ne avresti bisogno di uno più complesso.

Dipende da quale caso è "tipico", poiché le eccezioni dovrebbero modellare, beh, condizioni atipiche. Pertanto, se il caso tipico è che l'attributo istanza dovrebbe esistere, utilizzare il secondo stile di codice. Se non avere istanza è tipico come avere istanza , utilizzare il primo stile.

Nel caso specifico della creazione di un singleton, sono propenso ad andare con il primo stile, perché la creazione di un singleton il tempo iniziale è un tipico caso d'uso. : -)

Un po 'fuori tema nel modo di usarlo. I singoli sono sopravvalutati e uno "stato condiviso" Il metodo è altrettanto efficace e, soprattutto, molto pulito in Python, ad esempio:

class Borg:
    __shared_state = {}
    def __init__(self):
        self.__dict__ = self.__shared_state
    # and whatever else you want in your class -- that's all!

Ora ogni volta che lo fai:

obj = Borg()

avrà le stesse informazioni o, in qualche modo, sarà la stessa istanza.

Devo essere d'accordo con Chris. Ricorda, non ottimizzare fino a quando non è effettivamente necessario. Dubito davvero che verificare l'esistenza sarà un collo di bottiglia in qualsiasi programma ragionevole.

Ho visto http://code.activestate.com/recipes/52558/ anche per farlo. Copia senza commento di quel codice ("spam" è solo un metodo casuale che l'interfaccia di classe ha):

class Singleton:
    class __impl:
        def spam(self):
            return id(self)
    __instance = None
    def __init__(self):
        if Singleton.__instance is None:
            Singleton.__instance = Singleton.__impl()
        self.__dict__['_Singleton__instance'] = Singleton.__instance
    def __getattr__(self, attr):
        return getattr(self.__instance, attr)
    def __setattr__(self, attr, value):
        return setattr(self.__instance, attr, value)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top