Python dictionary "plus" behavior

I am trying to understand the exact mechanism for updating a python dictionary with d[key] += diff. I have helper classes for tracking magic method calls:

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)

Use these tools to release diving:

>>> d = sdict()
>>> d["a"] = 0
sdict.__setitem__
>>> d["a"] += 1
sdict.__getitem__
sdict.__setitem__
>>> d["a"]
sdict.__getitem__
1

We do not see any operation __iadd__being called here, which makes sense because the expression on the left side d["a"]returns an integer that the method does not implement __iadd__. We see how python magically transforms the operator +=into calls __getitem__and __setitem__.

Continuation:

>>> d["m"] = mutable()
sdict.__setitem__
>>> d["m"] += 1
sdict.__getitem__
mutable.__iadd__
sdict.__setitem__
>>> d["m"]
sdict.__getitem__
<__main__.mutable object at 0x106c4b710>

Here, the operator +=successfully calls the method __iadd__. It looks like the statement is +=actually used twice:

  • Once for magical translation on __getitem__and __setitem__challenges
  • __iadd__.

:

  • += __getitem__ __setitem__?
  • += ? python d["m"] = d["m"] + 1 ( __add__ __iadd__?)
+4
2

+= . , d['a'], .

, Python d['m'] (a __getitem__), +=, d['m'] ( __setitem__).

__iadd__ self , Python , . d.__setitem__('m', <return_value_from_d['m'].__iadd__(1)>).

, :

m = d['m']
m += 1
d['m'] = m

m .

mutable() , , , globals(), __getitem__ __setitem__.

:

(, , ) , , , .

d['m'] - ; __getitem__, __setitem__.

+8

, docs, __iadd__ , , , __setitem__ .

0

Source: https://habr.com/ru/post/1532914/


All Articles