LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 301|回复: 0

抽象协议支持

[复制链接]
发表于 2024-1-19 18:53:45 | 显示全部楼层 |阅读模式


Python 支持多种 抽象 '协议';被提供来使用这些接口的专门接口说明请在 抽象对象层 中查看。

这些抽象接口很多都是在 Python 实现开发的早期被定义的。 特别地,数字、映射和序列协议从一开始就已经是 Python 的组成部分。 其他协议则是后来添加的。 对于依赖某些来自类型实现的处理句柄例程的协议来说,较旧的协议被定义为类型对象所引用的处理句柄的可选块。 对于较新的协议来说在主类型对象中还有额外的槽位,并带有一个预设旗标位来指明存在该槽位并应当由解释器来检查。 (此旗标位并不会指明槽位值非 NULL 的情况,可以设置该旗标来指明一个槽位的存在,但此本位仍可能保持未填充的状态。)

PyNumberMethods   *tp_as_number;
PySequenceMethods *tp_as_sequence;
PyMappingMethods  *tp_as_mapping;
如果你希望你的对象的行为类似一个数字、序列或映射对象,那么你就要分别放置一个实现了 C 类型 PyNumberMethods, PySequenceMethods 或 PyMappingMethods, 的结构体的地址。 你要负责将适当的值填入这些结构体。 你可以在 Python 源代码发布版的 Objects 目录中找到这些对象各自的用法示例。

hashfunc tp_hash;
如果你选择提供此函数,则它应当为你的数据类型的实例返回一个哈希数值。 下面是一个简单的示例:

static Py_hash_t
newdatatype_hash(newdatatypeobject *obj)
{
    Py_hash_t result;
    result = obj->some_size + 32767 * obj->some_number;
    if (result == -1)
       result = -2;
    return result;
}
Py_hash_t 是一个宽度取决于具体平台的有符号整数类型。 从 tp_hash 返回 -1 表示发生了错误,这就是为什么你应当注意避免在哈希运算成功时返回它,如上面所演示的那样。

ternaryfunc tp_call;
此函数会在“调用”你的数据类型实例时被调用,举例来说,如果 obj1 是你的数据类型的实例而 Python 脚本包含了 obj1('hello'),则将发起调用 tp_call 处理句柄。

此函数接受三个参数:

self 是作为调用目标的数据类型实例。 如果调用是 obj1('hello'),则 self 为 obj1。

args 是包含调用参数的元组。 你可以使用 PyArg_ParseTuple() 来提取参数。

kwds 是由传入的关键字参数组成的字典。 如果它不为 NULL 且你支持关键字参数,则可使用 PyArg_ParseTupleAndKeywords() 来提取参数。 如果你不想支持关键字参数而它为非 NULL 值,则会引发 TypeError 并附带一个提示不支持关键字参数的消息。

下面是一个演示性的 tp_call 实现:

static PyObject *
newdatatype_call(newdatatypeobject *obj, PyObject *args, PyObject *kwds)
{
    PyObject *result;
    const char *arg1;
    const char *arg2;
    const char *arg3;

    if (!PyArg_ParseTuple(args, "sss:call", &arg1, &arg2, &arg3)) {
        return NULL;
    }
    result = PyUnicode_FromFormat(
        "Returning -- value: [%d] arg1: [%s] arg2: [%s] arg3: [%s]\n",
        obj->obj_UnderlyingDatatypePtr->size,
        arg1, arg2, arg3);
    return result;
}
/* Iterators */
getiterfunc tp_iter;
iternextfunc tp_iternext;
这些函数提供了对迭代器协议的支持。 这两个处理句柄都只接受一个形参,即它们被调用时所使用的实例,并返回一个新的引用。 当发生错误时,它们应设置一个异常并返回 NULL。 tp_iter 对应于 Python __iter__() 方法,而 tp_iternext 对应于 Python __next__() 方法。

任何 iterable 对象都必须实现 tp_iter 处理句柄,该处理句柄必须返回一个 iterator 对象。 下面是与 Python 类所应用的同一个指导原则:

对于可以支持多个独立迭代器的多项集(如列表和元组),则应当在每次调用 tp_iter 时创建并返回一个新的迭代器。

只能被迭代一次的对象(通常是由于迭代操作的附带影响,例如文件对象)可以通过返回一个指向自身的新引用来实现 tp_iter -- 并且为此还应当实现 tp_iternext 处理句柄。

任何 iterator 对象都应当同时实现 tp_iter 和 tp_iternext。 一个迭代器的 tp_iter 处理句柄应当返回一个指向该迭代器的新引用。 它的 tp_iternext 处理句柄应当返回一个指向迭代操作的下一个对象的新引用,如果还有下一个对象的话。 如果迭代已到达末尾,则 tp_iternext 可以返回 NULL 而不设置异常,或者也可以在返回 NULL 的基础上 额外 设置 StopIteration;避免异常可以产生更好的性能。 如果发生了实际的错误,则 tp_iternext 应当总是设置一个异常并返回 NULL。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表