回答此问题可获得 20 贡献值,回答如果被采纳可获得 50 分。
<p>我试图理解使用<code>d[key] += diff</code>更新python字典背后的确切机制。我有一些helper类来跟踪魔法方法调用:</p>
<pre><code>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)
</code></pre>
<p>有了这些工具,我们去潜水吧:</p>
<pre><code>>>> d = sdict()
>>> d["a"] = 0
sdict.__setitem__
>>> d["a"] += 1
sdict.__getitem__
sdict.__setitem__
>>> d["a"]
sdict.__getitem__
1
</code></pre>
<p>我们看不到在这里调用的任何<code>__iadd__</code>操作,这是有意义的,因为左侧表达式<code>d["a"]</code>返回一个不实现<code>__iadd__</code>方法的整数。我们确实看到python神奇地将<code>+=</code>操作符转换为<code>__getitem__</code>和<code>__setitem__</code>调用。</p>
<p>继续:</p>
<pre><code>>>> d["m"] = mutable()
sdict.__setitem__
>>> d["m"] += 1
sdict.__getitem__
mutable.__iadd__
sdict.__setitem__
>>> d["m"]
sdict.__getitem__
<__main__.mutable object at 0x106c4b710>
</code></pre>
<p>这里,<code>+=</code>运算符成功调用了<code>__iadd__</code>方法。看起来<code>+=</code>运算符实际上被使用了两次:</p>
<ul>
<li>对<code>__getitem__</code>和<code>__setitem__</code>调用的神奇转换</li>
<li>第二次进行<code>__iadd__</code>调用。</li>
</ul>
<p>我需要帮助的地方是:</p>
<ul>
<li>将<code>+=</code>运算符转换为<code>__getitem__</code>和<code>__setitem__</code>调用的确切技术机制是什么?</li>
<li>在第二个示例中,为什么要使用两次<code>+=</code>运算符?python是否将语句转换为<code>d["m"] = d["m"] + 1</code>(在这种情况下,我们不会看到<code>__add__</code>被调用而不是<code>__iadd__</code>?)</li>
</ul>