通用对象结构 — Python 文档

来自菜鸟教程
Python/docs/3.9/c-api/structures
跳转至:导航、​搜索

通用对象结构

在 Python 的对象类型定义中使用了大量结构。 本节介绍这些结构以及如何使用它们。

基本对象类型和宏

所有 Python 对象最终在对象在内存中的表示开始时共享少量字段。 这些由 PyObjectPyVarObject 类型表示,这些类型又由一些宏的扩展来定义,这些宏在所有其他 Python 的定义中也直接或间接使用对象。

type PyObject
所有对象类型都是这种类型的扩展。 这是一种包含 Python 需要将指向对象的指针视为对象的信息的类型。 在正常的“发布”构建中,它仅包含对象的引用计数和指向相应类型对象的指针。 实际上没有声明为 PyObject,但是每个指向 Python 对象的指针都可以转换为 PyObject*。 必须使用宏 Py_REFCNTPy_TYPE 来访问成员。
type PyVarObject
这是 PyObject 的扩展,添加了 ob_size 字段。 这仅用于具有 长度 某种概念的对象。 这种类型并不经常出现在 Python/C API 中。 必须使用宏 Py_REFCNTPy_TYPEPy_SIZE 来访问成员。
PyObject_HEAD

这是在声明表示没有变化长度的对象的新类型时使用的宏。 PyObject_HEAD 宏扩展为:

PyObject ob_base;

请参阅上面的 PyObject 文档。

PyObject_VAR_HEAD

这是在声明新类型时使用的宏,这些新类型表示长度因实例而异的对象。 PyObject_VAR_HEAD 宏扩展为:

PyVarObject ob_base;

请参阅上面的 PyVarObject 文档。

Py_TYPE(o)

该宏用于访问 Python 对象的 ob_type 成员。 它扩展为:

(((PyObject*)(o))->ob_type)
int Py_IS_TYPE(PyObject *o, PyTypeObject *type)

如果对象 o 类型为 type,则返回非零值。 否则返回零。 相当于:Py_TYPE(o) == type

3.9 版中的新功能。

void Py_SET_TYPE(PyObject *o, PyTypeObject *type)

将对象 o 类型设置为 类型

3.9 版中的新功能。

Py_REFCNT(o)

该宏用于访问 Python 对象的 ob_refcnt 成员。 它扩展为:

(((PyObject*)(o))->ob_refcnt)
void Py_SET_REFCNT(PyObject *o, Py_ssize_t refcnt)

将对象 o 引用计数器设置为 refcnt

3.9 版中的新功能。

Py_SIZE(o)

该宏用于访问 Python 对象的 ob_size 成员。 它扩展为:

(((PyVarObject*)(o))->ob_size)
void Py_SET_SIZE(PyVarObject *o, Py_ssize_t size)

将对象 o 的大小设置为 大小

3.9 版中的新功能。

PyObject_HEAD_INIT(type)

这是一个宏,它扩展为新的 PyObject 类型的初始化值。 这个宏扩展为:

_PyObject_EXTRA_INIT
1, type,
PyVarObject_HEAD_INIT(type, size)

这是一个宏,它扩展为新的 PyVarObject 类型的初始化值,包括 ob_size 字段。 这个宏扩展为:

_PyObject_EXTRA_INIT
1, type, size,


实现函数和方法

type PyCFunction

用于在 C 中实现大多数 Python 可调用函数的函数类型。 这种类型的函数采用两个 PyObject* 参数并返回一个这样的值。 如果返回值为 NULL,则应设置异常。 如果不是 NULL,则返回值被解释为 Python 中公开的函数的返回值。 该函数必须返回一个新的引用。

函数签名是:

PyObject *PyCFunction(PyObject *self,
                      PyObject *args);
type PyCFunctionWithKeywords

用于在 C 中实现 Python 可调用函数的函数类型,签名为 METH_VARARGS | METH_KEYWORDS。 函数签名是:

PyObject *PyCFunctionWithKeywords(PyObject *self,
                                  PyObject *args,
                                  PyObject *kwargs);
type _PyCFunctionFast

用于在 C 中实现 Python 可调用函数的函数类型,签名为 METH_FASTCALL。 函数签名是:

PyObject *_PyCFunctionFast(PyObject *self,
                           PyObject *const *args,
                           Py_ssize_t nargs);
type _PyCFunctionFastWithKeywords

用于在 C 中实现 Python 可调用函数的函数类型,签名为 METH_FASTCALL | METH_KEYWORDS。 函数签名是:

PyObject *_PyCFunctionFastWithKeywords(PyObject *self,
                                       PyObject *const *args,
                                       Py_ssize_t nargs,
                                       PyObject *kwnames);
type PyCMethod

用于在 C 中实现 Python 可调用函数的函数类型,签名为 METH_METHOD | METH_FASTCALL | METH_KEYWORDS。 函数签名是:

PyObject *PyCMethod(PyObject *self,
                    PyTypeObject *defining_class,
                    PyObject *const *args,
                    Py_ssize_t nargs,
                    PyObject *kwnames)

3.9 版中的新功能。

type PyMethodDef

用于描述扩展类型方法的结构。 这个结构有四个字段:

场地

C型

意义

ml_name

常量字符 *

方法名称

ml_meth

函数

指向 C 实现的指针

ml_flags

整数

指示应如何构造调用的标志位

ml_doc

常量字符 *

指向文档字符串的内容

ml_meth 是一个 C 函数指针。 函数可能是不同的类型,但它们总是返回 PyObject*。 如果函数不是 PyCFunction,编译器将需要在方法表中进行强制转换。 尽管 PyCFunction 将第一个参数定义为 PyObject*,但通常方法实现使用 self 对象的特定 C 类型。

ml_flags 字段是一个位字段,可以包含以下标志。 各个标志指示调用约定或绑定约定。

有这些调用约定:

METH_VARARGS
这是典型的调用约定,其中方法的类型为 PyCFunction。 该函数需要两个 PyObject* 值。 第一个是方法的 self 对象; 对于模块函数,它是模块对象。 第二个参数(通常称为 args)是一个表示所有参数的元组对象。 此参数通常使用 PyArg_ParseTuple()PyArg_UnpackTuple() 处理。
METH_VARARGS | METH_KEYWORDS
具有这些标志的方法必须是 PyCFunctionWithKeywords 类型。 该函数需要三个参数:selfargskwargs 其中 kwargs 是所有关键字参数的字典,也可能是 NULL 如果没有关键字参数。 通常使用 PyArg_ParseTupleAndKeywords() 处理参数。
METH_FASTCALL

仅支持位置参数的快速调用约定。 这些方法的类型为 _PyCFunctionFast。 第一个参数是 self,第二个参数是 PyObject* 值的 C 数组,表示参数,第三个参数是参数的数量(数组的长度)。

这不是 受限 API 的一部分。

3.7 版中的新功能。

METH_FASTCALL | METH_KEYWORDS

METH_FASTCALL 的扩展也支持关键字参数,方法类型为 _PyCFunctionFastWithKeywords。 关键字参数的传递方式与 vectorcall 协议 中的相同:还有一个额外的第四个 PyObject* 参数,它是一个表示关键字参数名称的元组(保证是字符串)或可能 NULL 如果没有关键字。 关键字参数的值存储在 args 数组中,在位置参数之后。

这不是 受限 API 的一部分。

3.7 版中的新功能。

METH_METHOD | METH_FASTCALL | METH_KEYWORDS

METH_FASTCALL | METH_KEYWORDS 的扩展支持 [X38X] 定义类 ,即包含相关方法的类。 定义类可能是 Py_TYPE(self) 的超类。

该方法需要是 PyCMethod 类型,与 METH_FASTCALL | METH_KEYWORDS 相同,在 self 之后添加 defining_class 参数。

3.9 版中的新功能。

METH_NOARGS
如果参数与 METH_NOARGS 标志一起列出,则没有参数的方法不需要检查是否给出了参数。 它们需要是 PyCFunction 类型。 第一个参数通常命名为 self 并且将保存对模块或对象实例的引用。 在所有情况下,第二个参数都是 NULL
METH_O
可以使用 METH_O 标志列出具有单个对象参数的方法,而不是使用 "O" 参数调用 PyArg_ParseTuple()。 它们的类型为 PyCFunction,带有 self 参数和一个表示单个参数的 PyObject* 参数。

这两个常量不用于指示调用约定,而是用于与类的方法一起使用时的绑定。 这些不能用于为模块定义的函数。 对于任何给定的方法,最多可以设置这些标志中的一个。

METH_CLASS
该方法将传递类型对象作为第一个参数而不是类型的实例。 这用于创建 类方法 ,类似于使用 classmethod() 内置函数时创建的内容。
METH_STATIC
该方法将通过 NULL 作为第一个参数而不是类型的实例。 这用于创建 静态方法 ,类似于使用 staticmethod() 内置函数时创建的内容。

另一个常量控制是否加载一个方法来代替具有相同方法名称的另一个定义。

METH_COEXIST
该方法将代替现有定义加载。 如果没有 METH_COEXIST,默认是跳过重复定义。 由于槽包装器在方法表之前加载,例如,sq_contains 槽的存在将生成名为 __contains__() 的包装方法,并阻止加载具有相同名称的相应 PyCFunction . 定义标志后,PyCFunction 将代替包装器对象加载,并将与插槽共存。 这很有用,因为对 PyCFunction 的调用比包装器对象调用更优化。


访问扩展类型的属性

type PyMemberDef

描述与 C 结构成员对应的类型的属性的结构。 它的字段是:

场地

C型

意义

name

常量字符 *

会员姓名

type

整数

C 结构体中成员的类型

offset

py_ssize_t

成员在类型的对象结构上的偏移量(以字节为单位)

flags

整数

指示字段是只读还是可写的标志位

doc

常量字符 *

指向文档字符串的内容

type 可以是对应于各种 C 类型的许多 T_ 宏之一。 在 Python 中访问该成员时,它会被转换为等效的 Python 类型。

宏名称

C型

T_SHORT

短的

着色

整数

T_LONG

T_FLOAT

漂浮

T_DOUBLE

双倍的

T_STRING

常量字符 *

T_OBJECT

对象 *

T_OBJECT_EX

对象 *

T_CHAR

字符

T_BYTE

字符

T_UBYTE

无符号字符

T_UINT

无符号整数

T_USHORT

无符号短

T_ULONG

无符号长

T_BOOL

字符

T_LONGLONG

长长的

T_ULONGLONG

无符号长长

T_PYSSIZET

py_ssize_t

T_OBJECTT_OBJECT_EX 的不同在于 T_OBJECT 返回 None 如果成员是 NULLT_OBJECT_EX 引发 ]属性错误。 尝试在 T_OBJECT 上使用 T_OBJECT_EX,因为 T_OBJECT_EXT_OBJECT 更正确地处理对该属性的 del 语句的使用。

flags 可以是 0 用于读写访问或 READONLY 用于只读访问。 将 T_STRING 用于 type 意味着 READONLYT_STRING 数据被解释为 UTF-8。 只能删除T_OBJECTT_OBJECT_EX成员。 (它们被设置为 NULL)。

堆分配类型(使用 PyType_FromSpec() 或类似方法创建),PyMemberDef 可能包含特殊成员 __dictoffset____weaklistoffset__ 和 [ X163X],对应类型对象中的tp_dictoffsettp_weaklistoffsettp_vectorcall_offset。 这些必须用 T_PYSSIZETREADONLY 定义,例如:

static PyMemberDef spam_type_members[] = {
    {"__dictoffset__", T_PYSSIZET, offsetof(Spam_object, dict), READONLY},
    {NULL}  /* Sentinel */
};
PyObject *PyMember_GetOne(const char *obj_addr, struct PyMemberDef *m)
获取属于地址 obj_addr 处的对象的属性。 该属性由 PyMemberDef m 描述。 出错时返回 NULL
int PyMember_SetOne(char *obj_addr, struct PyMemberDef *m, PyObject *o)
将属于地址 obj_addr 处的对象的属性设置为对象 o。 要设置的属性由 PyMemberDef m 描述。 如果成功返回 0,失败返回负值。
type PyGetSetDef

为类型定义类似属性的访问的结构。 另请参阅 PyTypeObject.tp_getset 插槽的描述。

场地

C型

意义

名称

常量字符 *

属性名

得到

吸气剂

C函数获取属性

二传手

可选的 C 函数来设置或删除属性,如果省略该属性是只读的

文档

常量字符 *

可选的文档字符串

关闭

空白 *

可选的函数指针,为 getter 和 setter 提供额外的数据

get 函数接受一个 PyObject* 参数(实例)和一个函数指针(关联的 closure):

typedef PyObject *(*getter)(PyObject *, void *);

它应该在成功时返回一个新的引用,或者在失败时返回 NULL 并设置异常。

set 函数采用两个 PyObject* 参数(实例和要设置的值)和一个函数指针(关联的 closure):

typedef int (*setter)(PyObject *, PyObject *, void *);

如果属性应该被删除,第二个参数是 NULL。 成功时应返回 0 或失败时返回 -1 并设置异常。