it-swarm.com.de

Wie benutze ich Punktnotation für Diktate in Python?

Ich bin sehr neu in Python und ich wünschte, ich könnte mit . Notation auf Werte einer dict zugreifen. 

Sagen wir, ich habe test so:

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

Aber ich wünschte, ich könnte test.name tun, um value zu bekommen. Ich habe es getan, indem ich die __getattr__-Methode in meiner Klasse folgendermaßen überschrieben habe:

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 tue:

test.name // I get value.

Aber das Problem ist, wenn ich nur test drucke, bekomme ich den Fehler als:

'Sorry no key matches'

Warum passiert dies?

36
batman

Diese Funktionalität ist bereits existiert in den Standardbibliotheken , daher empfehle ich, nur ihre 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 Zugriff auf Attribute erreicht, d. H. Sie können Anweisungen wie n.key = val und del n.key verwenden. 

Um wieder zu einem Diktat zu gelangen:

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

Die Schlüssel in Ihrem Diktat sollten die Zeichenfolge Bezeichner sein, damit der Zugriff auf Attribute ordnungsgemäß funktioniert. 

In Python 3.3 wurde ein einfacher Namespace hinzugefügt. Bei älteren Sprachversionen weist argparse.Namespace ein ähnliches Verhalten auf. 

57
wim

Ich gehe davon aus, dass Sie sich mit Javascript gut auskennen und diese Syntax ausleihen möchten. Ich kann Ihnen aus eigener Erfahrung sagen, dass dies keine gute Idee ist.

Es sieht sicher weniger wortreich und ordentlich aus; aber auf lange Sicht ist es nur dunkel. Bei Diagrammen handelt es sich um Diktate, und der Versuch, sie wie Objekte mit Attributen zu benehmen, führt wahrscheinlich zu (schlechten) Überraschungen.

Wenn Sie die Felder eines Objekts wie ein Wörterbuch bearbeiten müssen, können Sie jederzeit das interne __dict__-Attribut verwenden, wenn Sie es benötigen. Dann ist explizit klar, was Sie tun. Oder verwenden Sie getattr(obj, 'key'), um auch die Vererbungsstruktur und die Klassenattribute zu berücksichtigen.

Aber wenn Sie Ihr Beispiel lesen, scheinen Sie etwas anderes auszuprobieren ... Da der Punktoperator bereits im __dict__-Attribut ohne zusätzlichen Code nachschauen wird.

26
fortran

__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 es nicht in Ihrer Klasse implementieren, wird __getattr__ aufgerufen (ja, in Python-Methoden sind auch Attribute). Sie sollten nicht davon ausgehen, mit welchem ​​Schlüssel getattr aufgerufen wird, und vor allem muss __getattr__ einen AttributeError auslösen, wenn key nicht aufgelöst werden kann.

Als Randbemerkung: Verwenden Sie self.__dict__ nicht für den normalen Attributzugriff. Verwenden Sie einfach die einfache Attributnotation: 

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 keine älteren Versionen unterstützen müssen), können Sie einfach ein namedtuple verwenden: http://docs.python.org/2/ Bibliothek/collection.html # Collections.namedtuple

4

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)

3
Yann

Bei der Verwendung von __getattr__ müssen Sie vorsichtig sein, da es für eine Vielzahl von integrierten Python-Funktionen verwendet wird.

Versuchen Sie etwas davon ...

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>
2
Aya

Fügen Sie der Klasse eine __repr__()-Methode hinzu, damit Sie den anzuzeigenden Text anpassen können 

print text

Erfahren Sie hier mehr: http://www.diveintopython.net/object_oriented_framework/special_class_methods2.html

1
user2286078

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
0
Michael H.