Podklasowanie słownika Pythona w celu zastąpienia __setitem__
Buduję klasę, której podklasydict
i nadpisania__setitem__
. Chciałbym mieć pewność, że moja metoda zostanie wywołana we wszystkich przypadkach, w których elementy słownika mogłyby być ustawione.
Odkryłem trzy sytuacje, w których Python (w tym przypadku 2.6.4) nie wywołuje mojego przesłonięcia__setitem__
metoda podczas ustawiania wartości, a zamiast tego wywołujePyDict_SetItem
bezpośrednio
setdefault
metodawupdate
metodaJako bardzo prosty 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'}
Widać, że nadpisana metoda jest wywoływana tylko podczas jawnego ustawiania elementów. Aby Python zawsze dzwonił do mojego__setitem__
metody, musiałem ponownie zaimplementować te trzy metody, takie jak ta:
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]
Czy są jakieś inne metody, które muszę przesłonić, aby wiedzieć, że Python to zrobizawsze Zadzwoń do mojego__setitem__
metoda?
AKTUALIZACJA
Zgodnie z sugestią gs próbowałem podklasowania UserDict (właściwie IterableUserDict, ponieważ chcę iterować po kluczach) w ten sposób:
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)
Ta klasa wydaje się poprawnie nazywać moją__setitem__
nasetdefault
, ale to się nie nazywaupdate
lub gdy dane wstępne są dostarczane do konstruktora.
AKTUALIZACJA 2
Sugestia Petera Hansena skłoniła mnie do uważniejszego przyjrzenia się dictobject.c i zdałem sobie sprawę, że metoda aktualizacji może być nieco uproszczona, ponieważ wbudowany konstruktor słownika po prostu wywołuje wbudowaną metodę aktualizacji. Wygląda teraz tak:
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]