python-3.x - __ipow__ 当左侧对象返回 NotImplemented 时引发 TypeError
问题描述
如果我有两个对象A
和B
,我可以返回NotImplemented
forA
的__iadd__
方法并使用它的方法进行B
修改。A
__radd__
>>> class A():
... def __init__(self, val):
... self.val = val
... def __iadd__(self, other):
... return NotImplemented
... def __ipow__(self, other):
... return NotImplemented
...
>>> class B():
... def __init__(self, val):
... self.val = val
... def __radd__(self, other):
... return A(other.val + self.val)
... def __rpow__(self, other):
... return A(other.val ** self.val)
...
>>> a = A(2)
>>> b = B(2)
>>> a += b
>>> a.val
4
这似乎适用于所有就地运算符,除了__ipow__
aTypeError
被提出的地方。
>>> a **= b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for ** or pow(): 'A' and 'B'
为什么这里的行为不同?这是因为pow()
需要数字数据而失败吗?最好的解决方法是什么?
解决方案
Python 3.10+
此错误已在Python 3.10中修复
由于 的调度机制中的错误
**=
,定义__ipow__()
但返回 NotImplemented 的类将无法回退到x.__pow__(y)
andy.__rpow__(x)
。此错误已在 Python 3.10 中修复。
该片段现在按预期工作:
>>> a = A(2)
>>> b = B(2)
>>> a **= b
>>> a.val
4
由于二进制和三元运算的代码之间的不一致,这看起来像是一个错误(**=
由于与 3-argument 共享代码而由三元运算逻辑处理pow
)。二进制就地操作通过binary_iop1
,如果就地处理程序返回,则有代码回退到非就地例程NotImplemented
:
static PyObject *
binary_iop1(PyObject *v, PyObject *w, const int iop_slot, const int op_slot)
{
PyNumberMethods *mv = v->ob_type->tp_as_number;
if (mv != NULL) {
binaryfunc slot = NB_BINOP(mv, iop_slot);
if (slot) {
PyObject *x = (slot)(v, w);
if (x != Py_NotImplemented) {
return x;
}
Py_DECREF(x);
}
}
return binary_op1(v, w, op_slot);
}
但由于 3-argument 所需的代码差异pow
,**=
无法通过该代码路径,因此它有自己的临时处理:
PyObject *
PyNumber_InPlacePower(PyObject *v, PyObject *w, PyObject *z)
{
if (v->ob_type->tp_as_number &&
v->ob_type->tp_as_number->nb_inplace_power != NULL) {
return ternary_op(v, w, z, NB_SLOT(nb_inplace_power), "**=");
}
else {
return ternary_op(v, w, z, NB_SLOT(nb_power), "**=");
}
}
这种临时处理提交到就地或非就地方面,如果就地处理程序无法处理它,则没有回退。
推荐阅读
- javascript - 三个js动画动作不动画
- c# - 并行循环 C# 的最佳方法
- javascript - Vuejs:淡出过渡不起作用
- javascript - Object.defineProperty 重复属性值
- python - How To Fix : ValueError: Number of labels=21638 does not match number of samples=13
- vba - 使用 Excel VBA 从 Outlook 访问共享收件箱
- java - java8中的流切割
- postgresql - 获取在 Db.Query 调用后面使用的实际 sql 语句
- postgresql - Grafana Singlestat 在重复行上显示不同面板的相同值
- php - smt->close(); 之后什么也没有发生