Ich baue eine Klasse, die Unterklassen dict
und übersteuert __setitem__
. Ich möchte sicher sein, dass meine Methode in allen Fällen aufgerufen wird, in denen Wörterbucheinträge möglicherweise gesetzt werden können.
Ich habe drei Situationen entdeckt, in denen Python (in diesem Fall 2.6.4) mein überschriebenes __setitem__
Methode, wenn Werte gesetzt werden, und ruft stattdessen PyDict_SetItem
direkt
- Im Konstruktor
- In der
setdefault
Methode - In der
update
Methode
Das ist ein sehr einfacher Test:
class MyDict(dict):
def __setitem__(self, key, value):
print "Here"
super(MyDict, self).__setitem__(key, str(value).upper())
>>> a = MyDict(abc=123)
>>> a['def'] = 234
Here
>>> a.update({'ghi': 345})
>>> a.setdefault('jkl', 456)
456
>>> print a
{'jkl': 456, 'abc': 123, 'ghi': 345, 'def': '234'}
Sie sehen, dass die überschriebene Methode nur aufgerufen wird, wenn die Elemente explizit gesetzt werden. Um Python dazu zu bringen, immer meine __setitem__
Methode musste ich diese drei Methoden neu implementieren, etwa so:
class MyUpdateDict(dict):
def __init__(self, *args, **kwargs):
self.update(*args, **kwargs)
def __setitem__(self, key, value):
print "Here"
super(MyUpdateDict, self).__setitem__(key, value)
def update(self, *args, **kwargs):
if args:
if len(args) > 1:
raise TypeError("update expected at most 1 arguments, got %d" % len(args))
other = dict(args[0])
for key in other:
self[key] = other[key]
for key in kwargs:
self[key] = kwargs[key]
def setdefault(self, key, value=None):
if key not in self:
self[key] = value
return self[key]
Gibt es andere Methoden, die ich überschreiben muss, um zu wissen, dass Python wird immer rufen Sie meine __setitem__
Methode?
UPDATE
Per gs Vorschlag, habe ich versucht, UserDict (eigentlich, IterableUserDict, da ich über die Schlüssel iterieren möchte) wie folgt unterzuordnen:
from UserDict import *;
class MyUserDict(IterableUserDict):
def __init__(self, *args, **kwargs):
UserDict.__init__(self,*args,**kwargs)
def __setitem__(self, key, value):
print "Here"
UserDict.__setitem__(self,key, value)
Diese Klasse scheint korrekt meine __setitem__
en setdefault
aber er ruft es nicht auf update
oder wenn dem Konstruktor Anfangsdaten übergeben werden.
UPDATE 2
Peter Hansens Vorschlag veranlasste mich, dictobject.c genauer zu betrachten, und ich stellte fest, dass die Aktualisierungsmethode etwas vereinfacht werden könnte, da der eingebaute Wörterbuchkonstruktor ohnehin nur die eingebaute Aktualisierungsmethode aufruft. Jetzt sieht es so aus:
def update(self, *args, **kwargs):
if len(args) > 1:
raise TypeError("update expected at most 1 arguments, got %d" % len(args))
other = dict(*args, **kwargs)
for key in other:
self[key] = other[key]