moa*_*tra 6 python dictionary operators magic-methods mutators
我正在尝试了解使用更新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)
Run Code Online (Sandbox Code Playgroud)
有了这些工具,让我们去潜水:
>>> d = sdict()
>>> d["a"] = 0
sdict.__setitem__
>>> d["a"] += 1
sdict.__getitem__
sdict.__setitem__
>>> d["a"]
sdict.__getitem__
1
Run Code Online (Sandbox Code Playgroud)
我们没有看到__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>
Run Code Online (Sandbox Code Playgroud)
这里+=
操作员成功调用了一个__iadd__
方法.看起来+=
操作符实际上被使用了两次:
__getitem__
和__setitem__
调用__iadd__
通话.我需要帮助的地方如下:
+=
运营商转换为电话__getitem__
和__setitem__
电话的确切技术机制是什么?+=
操作员使用了两次?不是python将语句翻译成d["m"] = d["m"] + 1
(在这种情况下我们不会看到__add__
被调用而不是__iadd__
?)Mar*_*ers 10
在第一个示例中,您未将+=
运算符应用于字典.您将它应用于存储在d['a']
键中的值,这是一个完全不同的对象.
换句话说,Python将检索d['m']
(__getitem__
调用),将+=
运算符应用于该运算符,然后将该表达式的结果设置回d['m']
(__setitem__
调用).
该__iadd__
方法要么self
就地返回mutate,要么返回一个新对象,但Python无法确定该方法返回的内容.所以它必须d.__setitem__('m', <return_value_from_d['m'].__iadd__(1)>)
始终打电话.
如果你这样做会发生同样的事情:
m = d['m']
m += 1
d['m'] = m
Run Code Online (Sandbox Code Playgroud)
但没有m
全局命名空间中的额外名称.
如果mutable()
实例没有存储在字典中而是存储在全局命名空间中,则会发生完全相同的事件序列,但是直接在globals()
字典上,您将无法查看__getitem__
和__setitem__
调用.
这在扩充的分配参考文档中记录:
增强赋值评估目标(与正常赋值语句不同,它不能是解包)和表达式列表,执行特定于两个操作数上的赋值类型的二进制运算,并将结果赋给原始目标.
d['m']
目标在哪里; 在此处评估目标涉及__getitem__
,将结果分配回原始目标调用__setitem__
.
归档时间: |
|
查看次数: |
6046 次 |
最近记录: |