2013-04-29 12 views
26

Ich bin sehr neu zu Python und ich wünschte, ich könnte . Notation für den Zugriff auf dict Objekt in Python tun.Wie Punktnotation für Dict in Python verwenden?

Lets sagen, ich habe test wie folgt aus:

>>>test = dict() 
>>> test['name'] = 'value' 
>>> print(test['name']) 
value 

Aber ich wünschte, ich test.name tun könnte value zu bekommen. Infact Ich habe es durch Überschreiben der __getattr__ Methode in meiner Klasse wie folgt aus:

class JuspayObject: 

def __init__(self,response): 
    self.__dict__['_response'] = response 

def __getattr__(self,key): 
    try: 
     val = self._response[key] 
     return val 
    except KeyError,err: 
     sys.stderr.write('Sorry no key matches') 

und das funktioniert! wenn ich das tue:

test.name //I get value. 

Aber das Problem ist, wenn ich test nur drucken allein erhalte ich den Fehler:

'Sorry no key matches' 

warum das passiert !!!

Vielen Dank im Voraus.

+0

Sie müssen Superklasse __getattr__ aufrufen, wenn Sie nach Attribut fragen, das nicht in Ihrem dict ist. –

+0

@DavidHeffernan Hat eine Old-Style-Klasse wie das OP-Beispiel sogar eine Superklasse? – Aya

+0

@Aya Keine Ahnung. Wenn nicht, verwenden Sie eine neue Stilklasse. Wer benutzt noch immer alte Stilklassen? –

Antwort

23

Ich gehe davon aus, dass Sie in Javascript bequem sind und wollen leihen diese Art von Syntax ... Ich kann Ihnen durch persönliche 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. Dicts 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 manipulieren müssen, als ob sie ein Wörterbuch waren, kann man immer greifen die interne __dict__ Attribut zu verwenden, wenn Sie es brauchen, und dann ist es ausdrücklich klar, was Sie tun. Oder verwenden Sie getattr(obj, 'key'), um auch die Vererbungsstruktur und Klassenattribute zu berücksichtigen.

Aber durch das Lesen Ihres Beispiels scheint es, dass Sie etwas anderes versuchen ... Da der Punkt-Operator wird bereits in der Attribut ohne zusätzlichen Code suchen.

+3

Beispiel einer schlechten Überraschung: Wenn Sie einen Schlüssel im Diktat haben, das zufällig ein Python-Schlüsselwort ist, z. der String ''for'', dann ist der Attributzugriff fehlgeschlagen und es gibt keine elegante Möglichkeit, diesen Fall richtig zu behandeln. Die ganze Idee ist von Anfang an grundlegend gebrochen. – wim

+0

Auf der anderen Seite sorgt die automatische Vervollständigung für effizienteren, weniger fehleranfälligen Code. Das würde perfekt funktionieren * Wenn die dict-Struktur vordefiniert werden kann. * – roundar

2

Könnten Sie verwenden, um eine named tuple?

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) 

+0

Dies ist eine interessante Möglichkeit, auf eine Datenstruktur über die Punktnotation zuzugreifen, aber sie scheint nicht besonders kompatibel mit JSON oder dict zu sein. Es gibt Bibliotheken, die benannte Tupel unter den Covern verwenden, die JSON- und dict-Unterstützung bieten. Versuchen Sie https://github.com/dsc/bunch oder https://github.com/kennknowles/python-jsonpath-rw – MarkHu

28

Diese Funktionalität bereits exists in the standard libraries, so empfehle ich Ihnen nur ihre Klasse.

>>> from types import SimpleNamespace 
>>> d = {'key1': 'value1', 'key2': 'value2'} 
>>> n = SimpleNamespace(**d) 
>>> print(n) 
namespace(key1='value1', key2='value2') 
>>> n.key2 
'value2' 

Hinzufügen, Ändern und Entfernen von Werten mit regelmäßigem Attribute Zugriff erreicht wird, das heißt Sie Aussagen wie n.key = val und del n.key verwenden kann.

Um wieder zu einem dict zurück:

>>> vars(n) 
{'key1': 'value1', 'key2': 'value2'} 

Offensichtlich sollen die Schlüssel in Ihrem dict für Attribut Zugriff String-Bezeichner sein, um richtig zu arbeiten.

Einfacher Namespace wurde in Python 3.3 hinzugefügt. Für ältere Versionen der Sprache hat argparse.Namespace ähnliches Verhalten.

+0

[Fabric] (http://www.fabfile.org) hat auch eine nette minimale [Implementierung ] (https://github.com/fabric/fabric/blob/1.13.1/fabric/utils.py#L186), die ich auch [hier] gepostet habe (http://stackoverflow.com/a/41274937/307614). – Dave

2

Sie müssen vorsichtig sein, wenn Sie __getattr__ verwenden, da es für viele eingebaute Python-Funktionen verwendet wird.

versuchen, etwas so ...

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> 
+1

'__getattr__' wird nur als Fallback verwendet, wenn keine andere Suchregel übereinstimmt, also muss man nicht nach' self .__ dict __ [key] 'suchen, es wurde bereits gemacht, wenn' __getattr__' aufgerufen wird. Es genügt, 'AttributeError' zu starten, wenn die Suche auf self._response ['key'] fehlschlägt. –

+0

@brunodesthuilliers Sieht aus, als hättest du recht. Seltsam. Vielleicht war das früher nur in den Tagen von Python v1.5 notwendig. – Aya

2

__getattr__ wird als Ausweichlösung verwendet, wenn alle anderen Attribut-Lookup-Regeln gescheitert. Wenn Sie versuchen, Ihr Objekt zu "drucken", sucht Python nach einer __repr__ Methode, und da Sie es nicht in Ihrer Klasse implementieren, ruft es schließlich __getattr__ auf (ja, in Python-Methoden sind Attribute auch). Sie sollten nicht davon ausgehen, welcher Schlüssel getattr aufgerufen wird, und, am wichtigsten, __getattr__ muss ein AttributError auslösen, wenn es key nicht auflösen kann.

Als Randbemerkung: Sie self.__dict__ nicht für gewöhnliches Attribut Zugriff, verwenden Sie nur die Ebene Attribut Notation:

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) 

Nun, wenn Sie Ihre Klasse hat keine andere Verantwortung (und Ihre Python-Version ist> = 2.6 und Sie müssen nicht ältere Versionen unterstützen), können Sie einfach ein namedtuple verwenden: http://docs.python.org/2/library/collections.html#collections.namedtuple