Ich bin sehr neu in Python und ich wünschte, ich könnte .
Notation machen, um auf Werte von a zuzugreifen dict
.
Nehmen wir an, ich habe folgendes test
:
>>> test = dict()
>>> test['name'] = 'value'
>>> print(test['name'])
value
Aber ich wünschte, ich könnte tun test.name
, um zu bekommen value
. Tatsächlich habe ich die __getattr__
Methode in meiner Klasse folgendermaßen überschrieben :
class JuspayObject:
def __init__(self,response):
self.__dict__['_response'] = response
def __getattr__(self,key):
try:
return self._response[key]
except KeyError,err:
sys.stderr.write('Sorry no key matches')
und das funktioniert! wenn ich es tue:
test.name // I get value.
Aber das Problem ist, wenn ich nur test
alleine drucke, bekomme ich den Fehler als:
'Sorry no key matches'
Warum passiert das?
python
dictionary
nested
Batman
quelle
quelle
cgi.py
.Antworten:
Diese Funktionalität ist bereits in den Standardbibliotheken vorhanden. Ich empfehle daher, nur deren Klasse zu verwenden.
>>> from types import SimpleNamespace >>> d = {'key1': 'value1', 'key2': 'value2'} >>> n = SimpleNamespace(**d) >>> print(n) namespace(key1='value1', key2='value2') >>> n.key2 'value2'
Das Hinzufügen, Ändern und Entfernen von Werten wird durch regulären Attributzugriff erreicht, dh Sie können Anweisungen wie
n.key = val
und verwendendel n.key
.Um noch einmal zu einem Diktat zurückzukehren:
>>> vars(n) {'key1': 'value1', 'key2': 'value2'}
Die Schlüssel in Ihrem Diktat sollten Zeichenfolgenkennungen sein , damit der Attributzugriff ordnungsgemäß funktioniert.
In Python 3.3 wurde ein einfacher Namespace hinzugefügt. Hat für ältere Versionen der Sprache ein
argparse.Namespace
ähnliches Verhalten.quelle
myobj.subdict.subdict
Ich gehe davon aus, dass Sie sich in Javascript wohl fühlen und diese Art von Syntax ausleihen möchten ... Ich kann Ihnen aus eigener Erfahrung sagen, dass dies keine großartige Idee ist.
Es sieht sicher weniger ausführlich und ordentlich aus; aber auf lange Sicht ist es nur dunkel. Diktate sind Diktate, und der Versuch, sie wie Objekte mit Attributen zu verhalten, wird wahrscheinlich zu (schlechten) Überraschungen führen.
Wenn Sie die Felder eines Objekts so bearbeiten müssen, als wären sie ein Wörterbuch, können Sie jederzeit auf das interne
__dict__
Attribut zurückgreifen, wenn Sie es benötigen. Dann ist explizit klar, was Sie tun. Oder verwenden Siegetattr(obj, 'key')
, um auch die Vererbungsstruktur und die Klassenattribute zu berücksichtigen.Wenn Sie jedoch Ihr Beispiel lesen, versuchen Sie anscheinend etwas anderes ... Da der Punktoperator das
__dict__
Attribut bereits ohne zusätzlichen Code durchsucht.quelle
'for'
, schlägt der Attributzugriff fehl und es gibt keine elegante Möglichkeit, diesen Fall richtig zu behandeln. Die ganze Idee ist von Anfang an grundlegend gebrochen.Könnten Sie ein benanntes Tupel verwenden?
from collections import namedtuple Test = namedtuple('Test', 'name foo bar') my_test = Test('value', 'foo_val', 'bar_val') print(my_test) print(my_test.name)
quelle
from typing import NamedTuple
Zusätzlich zu dieser Antwort kann man auch Unterstützung für verschachtelte Dikte hinzufügen:
from types import SimpleNamespace class NestedNamespace(SimpleNamespace): def __init__(self, dictionary, **kwargs): super().__init__(**kwargs) for key, value in dictionary.items(): if isinstance(value, dict): self.__setattr__(key, NestedNamespace(value)) else: self.__setattr__(key, value) nested_namespace = NestedNamespace({ 'parent': { 'child': { 'grandchild': 'value' } }, 'normal_key': 'normal value', }) print(nested_namespace.parent.child.grandchild) # value print(nested_namespace.normal_key) # normal value
Beachten Sie, dass dies keine Punktnotation für Diktate unterstützt, die sich irgendwo in zB Listen befinden.
quelle
__getattr__
wird als Fallback verwendet, wenn alle anderen Attributsuchregeln fehlgeschlagen sind. Wenn Sie versuchen, Ihr Objekt zu "drucken", sucht Python nach einer__repr__
Methode, und da Sie sie nicht in Ihrer Klasse implementieren, wird sie schließlich aufgerufen__getattr__
(ja, in Python sind Methoden auch Attribute). Sie sollten nicht davon ausgehen, mit welchem Schlüssel getattr aufgerufen wird, und vor allem__getattr__
einen AttributeError auslösen müssen, wenn er nicht aufgelöst werden kannkey
.Als Randnotiz: Nicht
self.__dict__
für den normalen Attributzugriff verwenden, sondern nur die einfache Attributnotation verwenden:class JuspayObject: def __init__(self,response): # don't use self.__dict__ here self._response = response def __getattr__(self,key): try: return self._response[key] except KeyError,err: raise AttributeError(key)
Wenn Ihre Klasse keine andere Verantwortung hat (und Ihre Python-Version> = 2.6 ist und Sie ältere Versionen nicht unterstützen müssen), können Sie einfach ein benanntes Tupel verwenden: http://docs.python.org/2/library/ collection.html # collection.namedtuple
quelle
Sie müssen bei der Verwendung vorsichtig sein
__getattr__
, da es für viele integrierte Python-Funktionen verwendet wird.Versuchen Sie so etwas ...
class JuspayObject: def __init__(self,response): self.__dict__['_response'] = response def __getattr__(self, key): # First, try to return from _response try: return self.__dict__['_response'][key] except KeyError: pass # If that fails, return default behavior so we don't break Python try: return self.__dict__[key] except KeyError: raise AttributeError, key >>> j = JuspayObject({'foo': 'bar'}) >>> j.foo 'bar' >>> j <__main__.JuspayObject instance at 0x7fbdd55965f0>
quelle
__getattr__
wird nur als Fallback verwendet, wenn keine andere Suchregel übereinstimmt, sodass keine Suche erforderlich ist.self.__dict__[key]
Wenn dies__getattr__
aufgerufen wird , wurde dies bereits durchgeführt . Es reicht aus, nur zu erhöhen,AttributeError
wenn die Suche nach self._response ['key'] fehlgeschlagen ist.Fügen Sie
__repr__()
der Klasse eine Methode hinzu, damit Sie den anzuzeigenden Text anpassen könnenprint text
Weitere Informationen finden Sie hier: https://web.archive.org/web/20121022015531/http://diveintopython.net/object_oriented_framework/special_class_methods2.html
quelle