Dictionary mit Attributzugriff done right?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Im ASPN-Cookbook findet man viele Vorschläge dazu, aber welcher ist der beste? Mit geht es in einem konkreten Fall nur darum, lesende und (optional) schreibende Zugriffe mit der Punkt-Syntax formulieren zu können.

Wünschenswert kompakt und hinreichend korrekt scheint mir dieser Ansatz:

Code: Alles auswählen

class AttrDict(dict):

    def __init__(self, *args, **kwargs):
        dict.__init__(self, *args, **kwargs)

    def __getattr__(self, name):
        return self[name]
Wobei ich mich da frage, ob die Konstruktormethode nicht einfach weggelassen werden kann? Der der Elternklasse wird ja dann trotzdem noch automatisch aufgerufen.

Was gibt es sonst für Drawbacks, was muss man haben, worauf kann man verzichten, was ist böse? Ich hätte das gerne ein für alle mal geklärt gewusst :)
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Moin,

wenn du in deiner __init__-Methode nichts machst, brauchst du sie auch nicht, da hast du recht.

Sonst sieht's eigentlich ganz gut aus. Deine __getattr__-Methode wirft allerdings einen KeyError, wenn es name nicht gibt. Das könnte verwirrend sein, da man ja auf ein Attribut zugreifen will. Ich würde den KeyError abfangen und stattdessen einen AttributeError werfen.

Gruß,
Manuel
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Ah, guter Punkt.

Für das Setzen scheint diese Methode weit vorne zu sein:

Code: Alles auswählen

    def __setattr__(self, name, value):
        dict.__setattr__(self, name, value)
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Y0Gi hat geschrieben:Für das Setzen scheint diese Methode weit vorne zu sein:

Code: Alles auswählen

    def __setattr__(self, name, value):
        dict.__setattr__(self, name, value)
Wenn du das *so* willst, dann kannst du dir das wieder sparen.

Wenn du ein Attribut aber so setzen willst, dass es als key im dict landet, dann solltest du lieber __setitem__ nehmen ;-).
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Tatsache, da habe ich mich vertan :)
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Irgendwie vermisse ich hier die Kommentare der üblichen Verdächtigen :)
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Ist doch ein gutes Zeichen, oder? :)
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Y0Gi hat geschrieben:

Code: Alles auswählen

    def __setattr__(self, name, value):
        dict.__setattr__(self, name, value)
Das funktioniert doch nicht wirklich... Sollte es nicht so sein:

Code: Alles auswählen

    def __setattr__(self, name, value):
        self[name] = value
Aber warum möchtest du überhaupt so eine Klasse haben?
Willst du die Attribute auch als dict ansprechen oder geht es dir nur um das einfache Anzeigen, dabei geht das einfacher, z.b. so:

Code: Alles auswählen

class Test(object):
    def __str__(self):
        return str(self.__dict__)

t = Test()
t.foo = 1
t.bar = 2
print t

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

birkenfeld: Hm, auch wieder wahr :)

jens hat geschrieben:
Y0Gi hat geschrieben:

Code: Alles auswählen

    def __setattr__(self, name, value):
        dict.__setattr__(self, name, value)
Das funktioniert doch nicht wirklich... Sollte es nicht so sein:

Code: Alles auswählen

    def __setattr__(self, name, value):
        self[name] = value
Siehe oben bzgl. der Korrektur. Dein Code würde bei flüchtigem Hinsehen für mich eine Endlosschleife bedeuten.

Ansonsten geht es mir nicht nur um das Anzeigen, sondern eben um die Syntax. Das tippt sich so einfach leichter und wird daher ja auch von mancher Template-Engine so angeboten (u.a. auch von Smarty in der PHP-Welt). Ein wirklich handfestes Argument ist das allerdings nicht, zugegeben.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Y0Gi hat geschrieben:wird daher ja auch von mancher Template-Engine so angeboten (u.a. auch von Smarty in der PHP-Welt). Ein wirklich handfestes Argument ist das allerdings nicht, zugegeben.
Ja, aber wenn ich in Django oder Jinja ein ``something.0`` sehe, dann sieht das seltsam aus ;)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Y0Gi hat geschrieben:
jens hat geschrieben:Das funktioniert doch nicht wirklich... Sollte es nicht so sein:

Code: Alles auswählen

    def __setattr__(self, name, value):
        self[name] = value
Siehe oben bzgl. der Korrektur. Dein Code würde bei flüchtigem Hinsehen für mich eine Endlosschleife bedeuten.
Bei genaurem Hinsehen bemerkt man jedoch, dass `__setitem__` nicht `__setattr__` ist.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Gedacht war es so:

Code: Alles auswählen

class AttrDict1(dict):

    def __getattr__(self, name):
        return self[name]

    def __setattr__(self, name, value):
        self[name] = value


t = AttrDict1()
t.foo = 1
t.bar = 2
print t
print t.foo, t["foo"]
print t.bar, t["bar"]
Das kommt raus:
{'foo': 1, 'bar': 2}
1 1
2 2
Wenn es einem nur um die Ausgabe geht, könnte man es auch so machen:

Code: Alles auswählen

class Test(object):
    def __str__(self):
        return str(self.__dict__)

t = Test()
t.foo = 1
t.bar = 2
print t
print t.foo
print t.bar
Ausgabe:
{'foo': 1, 'bar': 2}
1
2
Allerdings ist mir immer noch nicht klar, warum man sowas wie die erste Variante braucht... Ich nehme dann lieber direkt ein dict pur...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten