In dem ich die Frage beantworte, die mir gestellt wurde
Warum bietet Python das nicht von Haus aus?
Ich vermute, dass es mit der Tatsache zu tun hat, dass Zen der Python : "Es sollte einen - und vorzugsweise nur einen - offensichtlichen Weg geben, dies zu tun." Dies würde zwei offensichtliche Wege schaffen, um auf Werte aus Wörterbüchern zuzugreifen: obj['key']
et obj.key
.
Vorbehalte und Fallstricke
Dazu gehören mögliche Unklarheiten und Verwirrungen im Code, z. B. könnte Folgendes für jemanden verwirrend sein sonst der Ihren Code zu einem späteren Zeitpunkt pflegen wird, oder sogar an Sie, wenn Sie eine Zeit lang nicht mehr damit arbeiten werden. Nochmals, von Zen : "Lesbarkeit zählt!"
>>> KEY = 'spam'
>>> d[KEY] = 1
>>> # Several lines of miscellaneous code here...
... assert d.spam == 1
Si d
instanziiert wird oder KEY
ist definiert oder d[KEY]
wird weit weg von dem Ort zugewiesen, an dem d.spam
verwendet wird, kann dies leicht zu Verwirrung darüber führen, was getan wird, da es sich hierbei nicht um eine allgemein gebräuchliche Redewendung handelt. Ich weiß, dass es das Potenzial hat, mich zu verwirren.
Wenn Sie außerdem den Wert von KEY
wie folgt (aber nicht ändern d.spam
), erhalten Sie jetzt:
>>> KEY = 'foo'
>>> d[KEY] = 1
>>> # Several lines of miscellaneous code here...
... assert d.spam == 1
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
AttributeError: 'C' object has no attribute 'spam'
IMO ist das den Aufwand nicht wert.
Andere Artikel
Wie bereits erwähnt, können Sie jedes beliebige hashfähige Objekt (nicht nur eine Zeichenkette) als Diktatschlüssel verwenden. Zum Beispiel,
>>> d = {(2, 3): True,}
>>> assert d[(2, 3)] is True
>>>
ist legal, aber
>>> C = type('C', (object,), {(2, 3): True})
>>> d = C()
>>> assert d.(2, 3) is True
File "<stdin>", line 1
d.(2, 3)
^
SyntaxError: invalid syntax
>>> getattr(d, (2, 3))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: getattr(): attribute name must be string
>>>
ist nicht. Damit haben Sie Zugriff auf den gesamten Bereich druckbarer Zeichen oder anderer hashbarer Objekte für Ihre Wörterbuchschlüssel, was beim Zugriff auf ein Objektattribut nicht der Fall ist. Dies ermöglicht solche Zaubereien wie eine zwischengespeicherte Objekt-Metaklasse, wie das Rezept aus der Python Kochbuch (Kap. 9) .
Wo ich ein Editorial schreibe
Ich bevorzuge die Ästhetik von spam.eggs
über spam['eggs']
(ich finde, es sieht sauberer aus), und ich habe wirklich angefangen, mich nach dieser Funktionalität zu sehnen, als ich die namedtuple
. Aber die Bequemlichkeit, Folgendes tun zu können, übertrumpft sie.
>>> KEYS = 'spam eggs ham'
>>> VALS = [1, 2, 3]
>>> d = {k: v for k, v in zip(KEYS.split(' '), VALS)}
>>> assert d == {'spam': 1, 'eggs': 2, 'ham': 3}
>>>
Dies ist ein einfaches Beispiel, aber ich verwende Dicts häufig in anderen Situationen als ich sie verwenden würde obj.key
Notation (z. B. wenn ich Voreinstellungen aus einer XML-Datei einlesen muss). In anderen Fällen, in denen ich versucht bin, eine dynamische Klasse zu instanziieren und ihr aus ästhetischen Gründen ein paar Attribute hinzuzufügen, verwende ich aus Konsistenzgründen weiterhin ein Diktat, um die Lesbarkeit zu verbessern.
Ich bin mir sicher, dass der Auftraggeber dieses Problem längst zu seiner Zufriedenheit gelöst hat, aber wenn er diese Funktionalität immer noch haben möchte, dann schlage ich vor, dass er eines der Pakete von pypi herunterlädt, das sie bereitstellt:
Bündel ist diejenige, mit der ich mehr vertraut bin. Unterklasse von dict
Damit haben Sie alle diese Funktionen.
AttrDict scheint auch ziemlich gut zu sein, aber ich bin nicht so vertraut damit und habe die Quelle nicht so detailliert durchgesehen Bündel .
- Süchtig Wird aktiv gepflegt und bietet attr-ähnlichen Zugang und mehr.
- Wie in den Kommentaren von Rotareti erwähnt, ist Bunch veraltet, aber es gibt einen aktiven Fork namens Munch .
Um die Lesbarkeit seines Codes zu verbessern, empfehle ich jedoch dringend, dass er no seine Notationsstile mischen. Wenn er diese Notation bevorzugt, sollte er einfach ein dynamisches Objekt instanziieren, ihm die gewünschten Attribute hinzufügen und das Ganze abhaken:
>>> C = type('C', (object,), {})
>>> d = C()
>>> d.spam = 1
>>> d.eggs = 2
>>> d.ham = 3
>>> assert d.__dict__ == {'spam': 1, 'eggs': 2, 'ham': 3}
Darin aktualisiere ich, um eine Folgefrage in den Kommentaren zu beantworten
In den Kommentaren (unten), Elmo fragt:
Und wenn Sie noch einen Schritt weiter gehen wollen? ( Bezug nehmend auf Typ(...) )
Ich habe diesen Anwendungsfall zwar noch nie benutzt (auch hier neige ich dazu, verschachtelte dict
für Konsistenz), funktioniert der folgende Code:
>>> C = type('C', (object,), {})
>>> d = C()
>>> for x in 'spam eggs ham'.split():
... setattr(d, x, C())
... i = 1
... for y in 'one two three'.split():
... setattr(getattr(d, x), y, i)
... i += 1
...
>>> assert d.spam.__dict__ == {'one': 1, 'two': 2, 'three': 3}