Подкласс Python словарь для переопределения __setitem__
Я строю класс, который подклассыdict
и переопределяет__setitem__
, Я хотел бы быть уверен, что мой метод будет вызываться во всех случаях, когда элементы словаря могут быть установлены.
Я обнаружил три ситуации, когда Python (в данном случае 2.6.4) не вызывает мой переопределенный__setitem__
метод при установке значений, а вместо этого вызываетPyDict_SetItem
непосредственно
setdefault
методвupdate
методКак очень простой тест:
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'}
Вы можете видеть, что переопределенный метод вызывается только при явной установке элементов. Чтобы Python всегда вызывал мой__setitem__
метод, мне пришлось переопределить эти три метода, как это:
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]
Есть ли другие методы, которые мне нужно переопределить, чтобы знать, что Python будетвсегда позвони мне__setitem__
метод?
ОБНОВИТЬ
Согласно предложению gs, я попытался создать подкласс UserDict (на самом деле, IterableUserDict, поскольку я хочу перебирать ключи) следующим образом:
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)
Этот класс, кажется, правильно называть мой__setitem__
наsetdefault
, но это не вызываетupdate
или когда начальные данные передаются в конструктор.
ОБНОВЛЕНИЕ 2
Предложение Питера Хансена заставило меня более внимательно посмотреть на dictobject.c, и я понял, что метод обновления можно немного упростить, так как встроенный конструктор словаря просто вызывает встроенный метод обновления в любом случае. Теперь это выглядит так:
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]