[Python-de] UserDict.UserDict vs. dict

Peter Otten __peter__ at web.de
So Feb 16 18:19:28 CET 2014


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 */




Mehr Informationen über die Mailingliste python-de