
Feb. 16, 2014
12:19 p.m.
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 */