介绍
此 PEP 描述了 Python 2.0 的增强分配建议。这 PEP 跟踪此功能的状态和所有权,计划推出 在 Python 2.0 中。它包含对功能的描述并概述了更改 支持该功能所必需的。本 PEP 总结了在 邮件列表论坛 ,并提供 URL 以获取更多信息,其中 适当。此文件的 CVS 修订历史记录包含最终的 历史记录。
建议的语义
向 Python 添加增强赋值的拟议补丁引入了 以下新运算符:
+= -= *= /= %= **= <<= >>= &= ^= |=
它们实现与普通二进制形式相同的运算符,除了 当左侧对象支持操作时,操作就地完成,并且 左侧只评估一次。
它们真正表现为增强任务,因为它们执行所有 正常的加载和存储操作,除了二进制操作之外,它们还 打算做。因此,给定表达式:
x += y
加载对象,然后添加到其中,生成 对象被存储回原来的位置。执行的精确操作 这两个参数取决于 的类型,可能还有 的类型。xyxy
Python 中增强赋值背后的想法是,它不仅仅是一个更容易的 编写存储二进制运算结果的常见做法的方法 在其左手操作数中,也是所讨论的左手操作数的一种方式 要知道它应该自行操作,而不是创建修改后的 自身的副本。
为了实现这一点,在 Python 类中添加了许多新的钩子,并且 C 扩展类型,当相关对象用作 增强分配操作的左侧。如果类或类型 不实现就地钩子,普通钩子为特定的 使用二进制运算。
因此,给定一个实例对象,表达式:x
x += y
尝试调用 ,这是 的就地变体。如果不存在,则尝试, 最后,如果也丢失了。没有 的右侧变体,因为这需要知道如何就地修改,这至少可以说是不安全的。 钩子的行为应类似于 ,返回 要分配给的操作的结果(可能是 ) 变量 .x.__iadd__(y)
__add__
__iadd__
x.__add__(y)
y.__radd__(x)
__add__
__iadd__
y
x
__iadd__
__add__
self
x
对于 C 扩展类型,钩子是 和 结构的成员。一些特殊的语义适用于使 使用这些方法,以及 Python 实例对象和 C 类型的混合, 尽可能不令人惊讶。PyNumberMethods
PySequenceMethods
在一般情况下(或使用 API 函数的类似情况),正在操作的主体对象是 。这与普通的二进制运算不同,在二进制运算中,可以认为是合作的,因为与二进制运算不同, 无法交换就地操作中的操作数。但是,就地 就地修改时,操作确实回退到正常的二进制操作 不受支持,导致以下规则:x <augop> y
PyNumber_InPlace
x
x
y
如果左侧对象 () 是一个实例对象,并且它有一个方法,则调用该函数作为参数。如果 强制成功,生成的左侧对象是不同的对象 比,停止就地处理它并调用相应的函数 对于正常的二进制运算,强制 和 参数。操作的结果是该函数返回的任何结果。
x
__coerce__
y
x
x
y
如果胁迫没有产生不同的对象,或者没有 定义一个方法,并具有适合此操作的方法,调用该方法作为参数,并且 操作的结果是该方法返回的任何结果。
x
x
__coerce__
x
__ihook__
y
否则,如果左侧对象不是实例对象,而是其类型 确实为此操作定义就地函数,调用该函数 with 和 as 参数,操作的结果是 无论该函数返回什么。
x
y
请注意,在这种情况下,不会对任何一个或进行胁迫,并且 对于 C 类型接收实例对象作为 第二个论点;这是普通二进制文件不会发生的事情 操作。
x
y
否则,完全按照正常的二进制操作(非就地)进行处理, 包括争论胁迫。简而言之,如果任一参数是实例 对象,则通过 和 解析操作。否则,这两个对象都是 C 类型,并且它们是强制的 并传递给相应的函数。
__coerce__
__hook__
__rhook__
如果找不到处理操作的方法,请使用 特定于操作的错误消息。
TypeError
存在一些特殊的大小写来解释 和 的情况, 对序列有特殊含义:for , sequence 串联,如果 C 类型定义 或 ,则不会强制执行任何操作。对于 ,序列重复,在调用 和 之前转换为 C 整数。即使 instance,但不是 if 是一个实例。
+
*
+
sq_concat
sq_inplace_concat
*
y
sq_inplace_repeat
sq_repeat
y
x
in-place 函数应始终返回一个新引用,或者返回对 旧对象(如果操作确实是就地执行的),或者是新对象 对象。x
理由
将此功能添加到 Python 有两个主要原因: 简单 表达式,并支持就地操作。最终结果是一种权衡 介于句法的简单性和表达的简单性之间;像大多数新人一样 功能,增强分配不会添加任何以前的内容 不可能的。它只是使这些事情更容易做到。
添加增强赋值将使 Python 的语法更加复杂。相反 在单个赋值操作中,现在有 12 个赋值操作, 其中 11 个还执行二进制操作。然而,这十一个新 转让形式很容易理解为转让之间的耦合 和二进制运算,它们不需要大的概念飞跃 理解。此外,具有增强赋值的语言具有 表明它们是一个流行的、经常使用的功能。表单表达式:
<x> = <x> <operator> <y>
在这些语言中足够常见,使额外的语法变得值得,并且 Python 的这些表达式并没有明显减少。相当 事实上,恰恰相反,因为在 Python 中,您还可以将列表与 二进制运算符,这是经常做的事情。写上面 表达为:
<x> <operator>= <y>
既可读性强,又不容易出错,因为它对 读者是被改变的,而不是被改变的 被几乎,但不完全不同的东西所取代。<x><x><x>
新的就地操作对于矩阵计算和 其他需要大型对象的应用程序。为了高效处理 有了可用的程序内存,这样的软件包就不能盲目地使用 当前二进制运算。因为这些操作总是会创建一个新的 对象,将单个项目添加到现有(大型)对象将导致 复制整个对象(这可能会导致应用程序用完 memory),添加单个项目,然后可能删除原始对象, 取决于引用计数。
若要变通解决此问题,包当前必须使用方法或 就地修改对象的函数,其可读性肯定低于 增强赋值表达式。增强赋值并不能解决所有问题 这些包的问题,因为某些操作无法用 一开始的二进制运算符集有限,但这是一个开始。PEP 211 正在考虑增加新的运营商。
新方法
建议的实现添加了以下 11 个可能的钩子,这些钩子 Python 类可以实现以重载增强的赋值操作:
__iadd__ __isub__ __imul__ __idiv__ __imod__ __ipow__ __ilshift__ __irshift__ __iand__ __ixor__ __ior__
i in 代表就地。__iadd__
对于 C 扩展类型,将添加以下结构成员。
自:PyNumberMethods
binaryfunc nb_inplace_add; binaryfunc nb_inplace_subtract; binaryfunc nb_inplace_multiply; binaryfunc nb_inplace_divide; binaryfunc nb_inplace_remainder; binaryfunc nb_inplace_power; binaryfunc nb_inplace_lshift; binaryfunc nb_inplace_rshift; binaryfunc nb_inplace_and; binaryfunc nb_inplace_xor; binaryfunc nb_inplace_or;
自:PySequenceMethods
binaryfunc sq_inplace_concat; intargfunc sq_inplace_repeat;
为了保持二进制兼容性,TypeObject 成员是 用于确定有问题的 TypeObject 是否为 这些插槽。直到二进制兼容性彻底中断(这可能 或者可能不会在 2.0 之前发生)想要使用新结构之一的代码 成员必须首先检查它们是否可用于宏:tp_flagsPyType_HasFeature()
if (PyType_HasFeature(x->ob_type, Py_TPFLAGS_HAVE_INPLACE_OPS) && x->ob_type->tp_as_number && x->ob_type->tp_as_number->nb_inplace_add) { /* ... */
甚至在测试方法槽的值之前,也必须进行此检查!宏仅测试插槽是否可用,而不测试插槽是否可用 它们充满了方法与否。NULL
实现
当前实现的增强赋值 [2] 除了 已经涵盖的方法和插槽,13 个新字节码和 13 个新 API 功能。
API 函数只是当前二进制操作的就地版本 API函数:
PyNumber_InPlaceAdd(PyObject *o1, PyObject *o2); PyNumber_InPlaceSubtract(PyObject *o1, PyObject *o2); PyNumber_InPlaceMultiply(PyObject *o1, PyObject *o2); PyNumber_InPlaceDivide(PyObject *o1, PyObject *o2); PyNumber_InPlaceRemainder(PyObject *o1, PyObject *o2); PyNumber_InPlacePower(PyObject *o1, PyObject *o2); PyNumber_InPlaceLshift(PyObject *o1, PyObject *o2); PyNumber_InPlaceRshift(PyObject *o1, PyObject *o2); PyNumber_InPlaceAnd(PyObject *o1, PyObject *o2); PyNumber_InPlaceXor(PyObject *o1, PyObject *o2); PyNumber_InPlaceOr(PyObject *o1, PyObject *o2); PySequence_InPlaceConcat(PyObject *o1, PyObject *o2); PySequence_InPlaceRepeat(PyObject *o, int count);
它们调用 Python 类钩子(如果任一对象是 Python class instance) 或 C 类型的 number 或 sequence 方法。
新的字节码是:
INPLACE_ADD INPLACE_SUBTRACT INPLACE_MULTIPLY INPLACE_DIVIDE INPLACE_REMAINDER INPLACE_POWER INPLACE_LEFTSHIFT INPLACE_RIGHTSHIFT INPLACE_AND INPLACE_XOR INPLACE_OR ROT_FOUR DUP_TOPX
字节码镜像字节码,不同之处在于 它们作为对 API 函数的调用实现。另外两个 字节码是实用程序字节码:除了旋转最上面的四个堆栈项外,其行为类似于。INPLACE_*BINARY_*InPlaceROT_FOURROT_THREE
DUP_TOPX是一个字节码,它采用一个参数,它应该是一个 介于 1 和 5(含)之间的整数,即要复制的项目数 在一个块中。给定这样的堆栈(列表的右侧是 堆栈的顶部):
[1, 2, 3, 4, 5]
DUP_TOPX 3将复制前 3 项,从而产生此堆栈:
[1, 2, 3, 4, 5, 3, 4, 5]
DUP_TOPX参数为 1 时与 相同。限制为 5 纯粹是实现限制。增强的实现 赋值只需要参数 2 和 3,并且可以 不使用这个新操作码,代价是相当多的 和 。DUP_TOPDUP_TOPXDUP_TOPROT_*
未解决的问题
API 只是普通 API 的子集: 仅支持增强分配所需的功能 语法包括在内。如果需要其他就地 API 函数,它们可以 稍后添加。PyNumber_InPlacePyNumber
字节码是一个方便的字节码,实际上不是 必要。应该考虑这个字节码是否值得拥有。 目前,此字节码似乎没有其他可能的用途。DUP_TOPX
版权
本文档已置于公共领域。
文章声明:以上内容(如有图片或视频在内)除非注明,否则均为腾龙猫勺儿原创文章,转载或复制请以超链接形式并注明出处。
本文作者:猫勺本文链接:https://www.jo6.cn/post/89.html
还没有评论,来说两句吧...