Ich schreibe meinen eigenen Container, der durch Attributaufrufe Zugriff auf ein Wörterbuch im Inneren gewähren muss. Die typische Verwendung des Behälters wäre wie folgt:
dict_container = DictContainer()
dict_container['foo'] = bar
...
print dict_container.foo
Ich weiß, dass es vielleicht dumm ist, so etwas zu schreiben, aber das ist die Funktionalität, die ich bereitstellen muss. Ich habe darüber nachgedacht, dies folgendermaßen umzusetzen:
def __getattribute__(self, item):
try:
return object.__getattribute__(item)
except AttributeError:
try:
return self.dict[item]
except KeyError:
print "The object doesn't have such attribute"
Ich bin nicht sicher , ob verschachtelter try / except Blöcke sind eine gute Praxis , so eine andere Art und Weise zu verwenden wäre hasattr()
und has_key()
:
def __getattribute__(self, item):
if hasattr(self, item):
return object.__getattribute__(item)
else:
if self.dict.has_key(item):
return self.dict[item]
else:
raise AttributeError("some customised error")
Oder um einen von ihnen zu verwenden und einen Catch-Block wie folgt zu versuchen:
def __getattribute__(self, item):
if hasattr(self, item):
return object.__getattribute__(item)
else:
try:
return self.dict[item]
except KeyError:
raise AttributeError("some customised error")
Welche Option ist am pythonischsten und elegantesten?
if 'foo' in dict_container:
. Amen.Antworten:
Ihr erstes Beispiel ist vollkommen in Ordnung. Sogar die offiziellen Python-Dokumente empfehlen diesen als EAFP bekannten Stil .
Persönlich vermeide ich lieber das Verschachteln, wenn es nicht notwendig ist:
PS.
has_key()
ist in Python 2 schon lange veraltet. Verwenden Sieitem in self.dict
stattdessen.quelle
return object.__getattribute__(item)
ist falsch und erzeugt ein,TypeError
weil die falsche Anzahl von Argumenten übergeben wird. Es sollte stattdessen seinreturn object.__getattribute__(self, item)
.from None
in der letzten Zeile?Während es in Java in der Tat eine schlechte Praxis ist, Ausnahmen für die Flusskontrolle zu verwenden (hauptsächlich, weil Ausnahmen das JVM zwingen, Ressourcen zu sammeln ( mehr hier )), gibt es in Python zwei wichtige Prinzipien: Duck Typing und EAFP . Dies bedeutet im Grunde, dass Sie aufgefordert werden, ein Objekt so zu verwenden, wie Sie es sich vorstellen, und damit umzugehen, wenn die Dinge nicht so sind.
Zusammenfassend wäre das einzige Problem, dass Ihr Code zu stark eingerückt wird. Wenn Sie Lust dazu haben, versuchen Sie, einige der Verschachtelungen zu vereinfachen, wie von lqc vorgeschlagen
quelle
Seien Sie vorsichtig - in diesem Fall wird zuerst
finally
berührt, ABER auch übersprungen.quelle
finally
Blöcke werden ausgeführta(0)
, aber nur übergeordnete Blöcke werdenfinally-return
zurückgegeben.Für Ihr spezielles Beispiel müssen Sie sie nicht verschachteln. Wenn der Ausdruck im
try
Block erfolgreich ist, wird die Funktion zurückgegeben, sodass jeder Code nach dem gesamten Versuch / Ausnahme-Block nur ausgeführt wird, wenn der erste Versuch fehlschlägt. Sie können also einfach Folgendes tun:Sie zu verschachteln ist nicht schlecht, aber ich habe das Gefühl, es flach zu lassen, um die Struktur klarer zu machen: Sie probieren nacheinander eine Reihe von Dingen aus und geben die erste zurück, die funktioniert.
Im Übrigen möchten Sie vielleicht darüber nachdenken, ob Sie wirklich
__getattribute__
statt__getattr__
hier verwenden möchten . Die Verwendung__getattr__
vereinfacht die Arbeit, da Sie wissen, dass der normale Attributsuchprozess bereits fehlgeschlagen ist.quelle
Meiner Meinung nach wäre dies die pythonischste Art, damit umzugehen, obwohl und weil es Ihre Frage zur Diskussion stellt. Beachten Sie, dass dies definiert wird,
__getattr__()
anstatt__getattribute__()
dass dies bedeutet, dass nur die "speziellen" Attribute behandelt werden müssen, die im internen Wörterbuch gespeichert sind.quelle
except
Block in Python 3 zu einer verwirrenden Ausgabe führen kann. Dies liegt daran, dass Python 3 (gemäß PEP 3134) die erste Ausnahme (theKeyError
) als "Kontext" der zweiten Ausnahme (theAttributeError
) verfolgt und wenn sie die erreicht In der obersten Ebene wird ein Traceback gedruckt, der beide Ausnahmen enthält. Dies kann hilfreich sein, wenn eine zweite Ausnahme nicht erwartet wurde. Wenn Sie jedoch die zweite Ausnahme absichtlich auslösen, ist dies unerwünscht. Für Python 3.3 hat PEP 415 die Möglichkeit hinzugefügt, den Kontext mithilfe von zu unterdrückenraise AttributeError("whatever") from None
.KeyError
zu einemAttributeError
und es ist nützlich und angemessen zu zeigen, was in einem Traceback passiert ist.__getattr__
eine Ausnahme ausgelöst wird, ist der Fehler wahrscheinlich ein Tippfehler im Attributzugriff und kein Implementierungsfehler im Code der aktuellen Klasse. Das Anzeigen der früheren Ausnahme als Kontext kann dies durcheinander bringen. Und selbst wenn Sie den Kontext mit unterdrückenraise Whatever from None
, können Sie bei Bedarf über auf die vorherige Ausnahme zugreifenex.__context__
.__getattribute__()
.In Python ist es einfacher, um Vergebung zu bitten als um Erlaubnis. Schwitzen Sie nicht bei der Behandlung verschachtelter Ausnahmen.
(Außerdem werden
has*
sowieso fast immer Ausnahmen unter der Abdeckung verwendet.)quelle
Laut Dokumentation ist es besser, mehrere Ausnahmen durch Tupel oder ähnliches zu behandeln:
quelle
Ein gutes und einfaches Beispiel für verschachtelte Versuche / Ausnahmen könnte das Folgende sein:
Probieren Sie nun verschiedene Kombinationen aus und Sie erhalten das richtige Ergebnis:
[Natürlich haben wir Numpy, also müssen wir diese Funktion nicht erstellen]
quelle
Eine Sache, die ich gerne vermeiden möchte, ist das Auslösen einer neuen Ausnahme beim Umgang mit einer alten. Das Lesen der Fehlermeldungen ist verwirrend.
Zum Beispiel habe ich in meinem Code ursprünglich geschrieben
Und ich habe diese Nachricht bekommen.
Was ich wollte war folgendes:
Es hat keinen Einfluss darauf, wie Ausnahmen behandelt werden. In jedem Codeblock wäre ein KeyError abgefangen worden. Dies ist lediglich eine Frage des Erhaltens von Stilpunkten.
quelle
from None
aber für noch mehr Style - Punkte. :)Wenn try-exception-finally im finally-Block verschachtelt ist, bleibt das Ergebnis von "child" finally erhalten. Ich habe noch keine offizielle Erklärung gefunden, aber das folgende Code-Snippet zeigt dieses Verhalten in Python 3.6.
quelle
Ich denke nicht, dass es darum geht, pythonisch oder elegant zu sein. Es geht darum, Ausnahmen so weit wie möglich zu verhindern. Ausnahmen sollen Fehler behandeln, die in Code oder Ereignissen auftreten können, über die Sie keine Kontrolle haben. In diesem Fall haben Sie die volle Kontrolle, wenn Sie prüfen, ob ein Element ein Attribut oder ein Wörterbuch ist. Vermeiden Sie daher verschachtelte Ausnahmen und bleiben Sie bei Ihrem zweiten Versuch.
quelle