小编给大家分享一下python中增强算术赋值是什么,希望大家阅读完这篇文章后大所收获、下面让我们一起去探讨吧!
介绍
python有一种叫做<代码>增强算术赋值> 代码(增强算法分配)的东西。可能你不熟悉这个叫法,其实就是在做数学运算的同时进行赋值,例如a -=b就是减法的增强算术赋值。
增强赋值是在python 2.0版本中加入进来的。(译注:在pep - 203中引入)
剖析<代码> -=代码>
因为python不允许覆盖式赋值,所以相比其它有特殊/魔术方法的操作,它实现增强赋值的方式可能跟你想象的不完全一样。
首先,要知道<代码> a - b=> 代码在语义上与<代码>=a - b> 代码相同。但也要意识到,如果你预先知道要将一个对象赋给一个变量名,相比<代码> a - b> 代码的盲操作,就可能会更高效。
例如,最起码的好处是可以避免创建一个新对象:如果可以就地修改一个对象,那么返回自我,就比重新构造一个新对象要高效。
因此,python提供了一个__isub__()方法。如果它被定义在赋值操作的左侧(通常称为左值),则会调用右侧的值(通常称为右值)。所以对于<代码> a - b=> 代码,就会尝试去调用a.__isub__ (b)。
如果调用的结果是NotImplemented,或者根本不存在结果,那么python会退回到常规的二元算术运算:<代码> a - b> 代码。(译注:作者关于二元运算的文章,译文在此)
最终无论用了哪种方法,返回值都会被赋值给一个。
下面是简单的伪代码,<代码> a - b=> 代码被分解成:
#实现-=b的伪代码如果hasattr (a,“__isub__"): _value=https://www.yisu.com/zixun/a.__isub__ (b)如果没有NotImplemented _value: 一个=_value别的:=- b del _value别的: a=a - b复制代码
归纳这些方法
由于我们已经实现了二元算术运算,因此归纳增强算术运算并不太复杂。
通过传入二元算术运算函数,并做一些自省(以及处理可能发生的TypeError),它可以被漂亮地归纳成:
def _create_binary_inplace_op (binary_op: _BinaryOp)→可调用的[[,],): binary_operation_name=binary_op.__name__ [2: 2] method_name=f" __i {binary_operation_name} __" 运算符=f" {binary_op._operator}=? def binary_inplace_op(左值:右值:任何,/)→任何: lvalue_type=类型(左值)试题:=debuiltins方法。除了AttributeError _mro_getattr (lvalue_type method_name):通过 其他: 价值=https://www.yisu.com/zixun/method(左值,右值)如果价值并非NotImplemented:试题:返回值返回binary_op(左值,右值)除了TypeError exc: #如果TypeError由于二进制算术运算符,抑制 #它我们可以适当提高>祝辞祝辞祝辞def测试():* *=b…在在在进口dis>在祝辞dis.dis LOAD_FAST(测试)1 0 0 (a) 2 LOAD_GLOBAL 0 (b) 4 INPLACE_POWER 6 STORE_FAST 0 (a) 8 LOAD_CONST 0(无)10 RETURN_VALUE复制代码
通过它,我找到了在eval循环中的<代码> INPLACE_POWER 代码>:
案例目标(INPLACE_POWER): { PyObject * exp=POP (); PyObject *基?最高(); PyObject * res=PyNumber_InPlacePower(基础、实验、Py_None); Py_DECREF(基地); Py_DECREF (exp); SET_TOP (res);如果(res==NULL)转到错误; 调度(); }复制代码
出处:github.com/python/cpyt…
然后找到<代码> PyNumber_InPlacePower() 代码>:
PyObject * PyNumber_InPlacePower (PyObject * v, PyObject * w, PyObject * z){如果(v→ob_type→tp_as_number,, v→ob_type→tp_as_number→nb_inplace_power !=NULL){返回ternary_op (v, w、z NB_SLOT (nb_inplace_power),“* *=?; 其他}{返回ternary_op (v, w、z NB_SLOT (nb_power),“* *=?; } }复制代码
出处:github.com/python/cpyt…
松了口气~代码显示如果定义了__ipow__,则会调用它,但是只在没有__ipow__时,才会调用__pow__。
然而,正确的做法应该是:<>强如果调用__ipow__时出问题,返回了NotImplemented或者根本不存在返回,那么就应该调用__pow__和__rpow__。强>
换句话说,当存在__ipow__时,以上代码会意外地跳过* * b的后备语义。
实际上,大约11个月前,这个问题被部分地发现,并提交了错误。我修复了该问题,并在python-dev上作了说明。
截至目前,这似乎会在Python 3.10中修复,我们还需要在3.8和3.9的文档中添加关于* *=有bug的通知(该问题可能很早就有了,但较旧的Python版本已处于仅安全维护模式,因此文档不会变更)。
修复的代码很可能不会被移植,因为它是语义上的变化,并且很难判断是否有人意外地依赖了有问题的语义。但是这个问题花了很长时间才被注意到,这就表明* *=的使用并不广泛,否则问题早就被发现了。