Überprüfen auf Mitglied Existenz in Python
-
03-07-2019 - |
Frage
Ich möchte regelmäßig überprüfen, ob ein Objekt ein Mitglied hat oder nicht. Ein Beispiel ist die Schaffung eines Singleton in einer Funktion. Zu diesem Zweck können Sie hasattr
wie folgt verwenden:
class Foo(object):
@classmethod
def singleton(self):
if not hasattr(self, 'instance'):
self.instance = Foo()
return self.instance
Aber man kann dies auch tun:
class Foo(object):
@classmethod
def singleton(self):
try:
return self.instance
except AttributeError:
self.instance = Foo()
return self.instance
Ist eine Methode besser von der anderen Seite?
Edit: wurde hinzugefügt @classmethod
... Aber beachten Sie, dass die Frage ist nicht , wie ein Singleton zu machen, sondern, wie die Anwesenheit eines Mitglieds in einem Objekt zu überprüfen .
Edit: Für dieses Beispiel eine typische Anwendung wäre:
s = Foo.singleton()
Dann s
ist ein Objekt vom Typ Foo
, die jedes Mal gleich. Und, in der Regel wird das Verfahren oft genannt wird.
Lösung
Das sind zwei verschiedene Methoden: №1 ist LBYL (sehen Sie vor dem Sprung) und №2 ist EAFP (einfacher bitten um Vergebung als Erlaubnis)
.Pythonistas legt nahe, dass typischerweise EAFP ist besser, mit Argumenten im Stil von „was ist, wenn ein Prozess die Datei zwischen der Zeit schafft sie es testen und die Zeit, die Sie versuchen, es selbst zu erstellen?“. Dieses Argument gilt hier nicht, aber es ist die allgemeine Idee. Ausnahmen sollten nicht so behandelt werden zu außergewöhnlich.
Performance-weise in Ihrem Fall -Da Ausnahme Manager einrichten (das try
Schlüsselwort) ist sehr billig in CPython während einer Ausnahme zu schaffen (das raise
Schlüsselwort und interne Ausnahme Schöpfung) ist das, was relativ expensive- ist mit der Methode №2 die Ausnahme würde nur einmal angehoben werden; danach, die Sie gerade die Eigenschaft verwenden.
Andere Tipps
Ich habe gerade versucht mal zu messen:
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
Auf meinem Rechner:
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
Es scheint, dass try / except schneller ist. Es scheint auch besser lesbar zu mir ohnehin von dem Fall, wurde dieser Test sehr einfach vielleicht würde Sie eine komplexere brauchen.
Es hängt davon ab, welchen Fall „typisch“ ist, weil Ausnahmen sollten, na ja, atypische Bedingungen modellieren. Also, wenn der typische Fall ist, dass das instance
Attribut existieren sollte, verwenden Sie dann den zweiten Code-Stil. Wenn nicht instance
, wie sie typisch ist instance
hat, dann die erste Art verwendet werden.
Im speziellen Fall von Singleton zu schaffen, ich bin geneigt, mit der ersten Art zu gehen, weil einem Singleton die Anfangszeit zu schaffen ein typischer Anwendungsfall ist. : -)
Ein wenig vom Thema in der Art und Weise, es zu benutzen. Singletons sind überbewertet, und eine "shared-state" Methode ist so effektiv, und vor allem, sehr sauber in Python, zum Beispiel:
class Borg:
__shared_state = {}
def __init__(self):
self.__dict__ = self.__shared_state
# and whatever else you want in your class -- that's all!
Nun jedes Mal, wenn Sie tun:
obj = Borg()
es wird die gleiche Information hat, oder, sein etwas die gleiche Instanz.
Ich habe mit Chris zu vereinbaren. Denken Sie daran, nicht zu optimieren, bis Sie wirklich so tun müssen. Ich wirklich Zweifel Überprüfung auf Existenz zu einem Engpass in jedem vernünftigen Programm sein wird.
Ich sehe tat http://code.activestate.com/recipes/52558/ als eine Möglichkeit, dies zu tun, auch. Unkommentiert Kopie des Codes ( „Spam“ ist nur eine zufällige Methode der Klasse Schnittstelle):
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)