Seite 1 von 1

Dictionary mit Attributzugriff done right?

Verfasst: Sonntag 6. April 2008, 21:25
von Y0Gi
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 :)

Verfasst: Montag 7. April 2008, 09:01
von helduel
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

Verfasst: Montag 7. April 2008, 11:04
von Y0Gi
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)

Verfasst: Montag 7. April 2008, 12:16
von helduel
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 ;-).

Verfasst: Montag 7. April 2008, 12:26
von Y0Gi
Tatsache, da habe ich mich vertan :)

Verfasst: Dienstag 8. April 2008, 12:03
von Y0Gi
Irgendwie vermisse ich hier die Kommentare der üblichen Verdächtigen :)

Verfasst: Dienstag 8. April 2008, 20:12
von birkenfeld
Ist doch ein gutes Zeichen, oder? :)

Verfasst: Mittwoch 9. April 2008, 09:04
von jens
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

Verfasst: Mittwoch 9. April 2008, 21:00
von Y0Gi
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.

Verfasst: Mittwoch 9. April 2008, 21:25
von Leonidas
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 ;)

Verfasst: Donnerstag 10. April 2008, 12:59
von Trundle
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.

Verfasst: Donnerstag 10. April 2008, 13:04
von jens
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...