UserDict.UserDict vs. dict

Hallo zusammen, kann mich mal jemand erhellen, was der feine Unterschied ist, wenn ich eine Klasse von UserDict.UserDict oder dict ableite und die in der Python Format String Syntax verwende? Gegeben ist der Code unten und ich würde in beiden Fällen die selbe Ausgabe erwarten (Python 2.7.5). Ist aber unterschiedlich: $python tmp/dict_template_test.py Str1stValueUserDict Classic: Foo a1 bar b1 Str1stValueUserDict New: Foo a1 bar b1 Str1stValueDict Classic: Foo a1 bar b1 Str1stValueDict New: Foo ['a1', 'a2'] bar ['b1', 'b2'] Warum? Ciao, Michael. ----------------------------- snip ----------------------------- import UserDict class Str1stValueUserDict(UserDict.UserDict): def __getitem__(self,key): return UserDict.UserDict.__getitem__(self,key)[0] e = { 'a':['a1','a2'], 'b':['b1','b2'], } e_1st = Str1stValueUserDict(e) print 'Str1stValueUserDict Classic:','Foo %(a)s bar %(b)s' % e_1st print 'Str1stValueUserDict New:','Foo {a} bar {b}'.format(**e_1st) class Str1stValueDict(dict): def __getitem__(self,key): return dict.__getitem__(self,key)[0] e_1st = Str1stValueDict(e) print 'Str1stValueDict Classic:','Foo %(a)s bar %(b)s' % e_1st print 'Str1stValueDict New:','Foo {a} bar {b}'.format(**e_1st)

Michael Ströder wrote: > Hallo zusammen, > > kann mich mal jemand erhellen, was der feine Unterschied ist, wenn ich > eine Klasse von UserDict.UserDict oder dict ableite und die in der Python > Format String Syntax verwende? > > Gegeben ist der Code unten und ich würde in beiden Fällen die selbe > Ausgabe erwarten (Python 2.7.5). > > Ist aber unterschiedlich: > > $python tmp/dict_template_test.py > Str1stValueUserDict Classic: Foo a1 bar b1 > Str1stValueUserDict New: Foo a1 bar b1 > Str1stValueDict Classic: Foo a1 bar b1 > Str1stValueDict New: Foo ['a1', 'a2'] bar ['b1', 'b2'] > > Warum? > > Ciao, Michael. > > ----------------------------- snip ----------------------------- > import UserDict > > class Str1stValueUserDict(UserDict.UserDict): > > def __getitem__(self,key): > return UserDict.UserDict.__getitem__(self,key)[0] > > e = { > 'a':['a1','a2'], > 'b':['b1','b2'], > } > > e_1st = Str1stValueUserDict(e) > > print 'Str1stValueUserDict Classic:','Foo %(a)s bar %(b)s' % e_1st > > print 'Str1stValueUserDict New:','Foo {a} bar {b}'.format(**e_1st) > > class Str1stValueDict(dict): > > def __getitem__(self,key): > return dict.__getitem__(self,key)[0] > > e_1st = Str1stValueDict(e) > > print 'Str1stValueDict Classic:','Foo %(a)s bar %(b)s' % e_1st > > print 'Str1stValueDict New:','Foo {a} bar {b}'.format(**e_1st) Ich glaube, dass der entscheidende Unterschied für dein Beispiel ist, dass Python durch den **-call implizit ein neues dict baut. Für dict-subclasses wird dabei ein optimierter code-path verwendet, der nicht auf __getitem__() zugreift. >>> class U(UserDict): ... def __getitem__(self, key): return 42 ... >>> u = U("aA bB cC".split()) >>> dict(u) {'c': 42, 'a': 42, 'b': 42} >>> class D(dict): ... def __getitem__(self, key): return 42 ... >>> d = D("aA bB cC".split()) >>> dict(d) {'c': 'C', 'a': 'A', 'b': 'B'} PS: Eine einzige Zeile müsste geändert werden, damit sich dict wie UserDict verhält: Python 3.4.0rc1+ (default:2ba583191550+, Feb 16 2014, 18:12:05) [GCC 4.6.1] on linux Type "help", "copyright", "credits" or "license" for more information. >>> class D(dict): ... def __getitem__(self, key): return 42 ... >>> d = D("aA bB cC".split()) >>> dict(d) {'b': 42, 'c': 42, 'a': 42} >>> [1]+ Angehalten ./python $ hg diff diff -r 2ba583191550 Objects/dictobject.c --- a/Objects/dictobject.c Tue Feb 11 18:40:56 2014 +0100 +++ b/Objects/dictobject.c Sun Feb 16 18:14:02 2014 +0100 @@ -1954,7 +1954,7 @@ return -1; } mp = (PyDictObject*)a; - if (PyDict_Check(b)) { + if (PyDict_CheckExact(b)) { other = (PyDictObject*)b; if (other == mp || other->ma_used == 0) /* a.update(a) or a.update({}); nothing to do */

Am 16.02.2014 17:34, schrieb Michael Ströder:
kann mich mal jemand erhellen, was der feine Unterschied ist, wenn ich eine Klasse von UserDict.UserDict oder dict ableite und die in der Python Format String Syntax verwende?
In Ergänzung zu Peters Antwort: - UserDict ist noch ein Überbleibsel aus der Zeit vor Python 2.0, in der man in Python nicht von den eingebauten Typen ableiten konnte. - UserDict ist daher auch keine "new style"-Klasse. - In Python 3 funktioniert die dict-Subklasse wie von dir erwartet. - Die Referenz-Dokumentation sagt zur **-Syntax nur: "If the syntax **expression appears in the function call, expression must evaluate to a mapping, the contents of which are treated as additional keyword arguments." http://docs.python.org/3/reference/expressions.html#index-37 Das lässt einigen Spielraum für die Interpretation offen ("evaluate to"), insbesondere da die Dokumentation zu __getitem__ nur von Auswirkungen auf den Zugriff auf Sequence/Mapping-Elemente über den []-Operator spricht. http://docs.python.org/3/reference/datamodel.html#object.__getitem__ Chris
participants (3)
-
Christopher Arndt
-
Michael Ströder
-
Peter Otten