PEP 203 – 增强作业

猫勺猫勺 04-24 111 阅读 0 评论

介绍

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__yx__iadd____add__selfx

对于 C 扩展类型,钩子是 和 结构的成员。一些特殊的语义适用于使 使用这些方法,以及 Python 实例对象和 C 类型的混合, 尽可能不令人惊讶。PyNumberMethodsPySequenceMethods

在一般情况下(或使用 API 函数的类似情况),正在操作的主体对象是 。这与普通的二进制运算不同,在二进制运算中,可以认为是合作的,因为与二进制运算不同, 无法交换就地操作中的操作数。但是,就地 就地修改时,操作确实回退到正常的二进制操作 不受支持,导致以下规则:x <augop> yPyNumber_InPlacexxy

  • 如果左侧对象 () 是一个实例对象,并且它有一个方法,则调用该函数作为参数。如果 强制成功,生成的左侧对象是不同的对象 比,停止就地处理它并调用相应的函数 对于正常的二进制运算,强制 和 参数。操作的结果是该函数返回的任何结果。x__coerce__yxxy

    如果胁迫没有产生不同的对象,或者没有 定义一个方法,并具有适合此操作的方法,调用该方法作为参数,并且 操作的结果是该方法返回的任何结果。xx__coerce__x__ihook__y

  • 否则,如果左侧对象不是实例对象,而是其类型 确实为此操作定义就地函数,调用该函数 with 和 as 参数,操作的结果是 无论该函数返回什么。xy

    请注意,在这种情况下,不会对任何一个或进行胁迫,并且 对于 C 类型接收实例对象作为 第二个论点;这是普通二进制文件不会发生的事情 操作。xy

  • 否则,完全按照正常的二进制操作(非就地)进行处理, 包括争论胁迫。简而言之,如果任一参数是实例 对象,则通过 和 解析操作。否则,这两个对象都是 C 类型,并且它们是强制的 并传递给相应的函数。__coerce____hook____rhook__

  • 如果找不到处理操作的方法,请使用 特定于操作的错误消息。TypeError

  • 存在一些特殊的大小写来解释 和 的情况, 对序列有特殊含义:for , sequence 串联,如果 C 类型定义 或 ,则不会强制执行任何操作。对于 ,序列重复,在调用 和 之前转换为 C 整数。即使 instance,但不是 if 是一个实例。+*+sq_concatsq_inplace_concat*ysq_inplace_repeatsq_repeatyx

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

版权

文档已置于公共领域。

The End 微信扫一扫

文章声明:以上内容(如有图片或视频在内)除非注明,否则均为腾龙猫勺儿原创文章,转载或复制请以超链接形式并注明出处。

本文作者:猫勺本文链接:https://www.jo6.cn/post/89.html

上一篇 下一篇

相关阅读

发表评论

访客 访客
快捷回复: 表情:
评论列表 (暂无评论,111人围观)

还没有评论,来说两句吧...

取消
微信二维码
微信二维码
支付宝二维码