Я пытаюсь понять точный механизм обновления словаря Python с помощью d[key] += diff
. У меня есть несколько вспомогательных классов для отслеживания вызовов магических методов:
class sdict(dict):
def __setitem__(self, *args, **kargs):
print "sdict.__setitem__"
return super(sdict, self).__setitem__(*args, **kargs)
def __delitem__(self, *args, **kargs):
print "sdict.__delitem__"
return super(sdict, self).__delitem__(*args, **kargs)
def __getitem__(self, *args, **kargs):
print "sdict.__getitem__"
return super(sdict, self).__getitem__(*args, **kargs)
def __iadd__(self, *args, **kargs):
print "sdict.__iadd__"
return super(sdict, self).__iadd__(*args, **kargs)
def __add__(self, *args, **kargs):
print "sdict.__add__"
return super(sdict, self).__add__(*args, **kargs)
class mutable(object):
def __init__(self, val=0):
self.value = val
def __iadd__(self, val):
print "mutable.__iadd__"
self.value = self.value + val
return self
def __add__(self, val):
print "mutable.__add__"
return mutable(self.value + val)
С этими инструментами приступим к погружению:
>>> d = sdict()
>>> d["a"] = 0
sdict.__setitem__
>>> d["a"] += 1
sdict.__getitem__
sdict.__setitem__
>>> d["a"]
sdict.__getitem__
1
Мы не видим, чтобы здесь вызывалась какая-либо операция __iadd__
, что имеет смысл, поскольку левое выражение d["a"]
возвращает целое число, которое не реализует метод __iadd__
. Мы видим, как Python волшебным образом преобразует оператор +=
в вызовы __getitem__
и __setitem__
.
Продолжение:
>>> d["m"] = mutable()
sdict.__setitem__
>>> d["m"] += 1
sdict.__getitem__
mutable.__iadd__
sdict.__setitem__
>>> d["m"]
sdict.__getitem__
<__main__.mutable object at 0x106c4b710>
Здесь оператор +=
успешно вызывает метод __iadd__
. Похоже, что оператор +=
используется дважды:
- Один раз за волшебный перевод на
__getitem__
и__setitem__
звонки - Второй раз для вызова
__iadd__
.
Мне нужна помощь в следующем:
- Каков точный технический механизм преобразования оператора
+=
в вызовы__getitem__
и__setitem__
? - Почему во втором примере оператор
+=
используется дважды? Разве python не переводит оператор вd["m"] = d["m"] + 1
(в этом случае мы не увидим, что__add__
вызывается вместо__iadd__
?)
sdict.__iadd__
никогда не вызывается, потому что у вас нет кода, который выполняет+=
для объектаsdict
. Вы выполняете только+=
для элементов вsdict
- в первом случае целое число, а во втором случаеmutable
. Но вы уже продемонстрировали, что понимаете это, поэтому я не уверен, в чем вопрос. - person dg99   schedule 22.03.2014