# 通用物件結構

大量的结构体被用于定义Python的对象类型。这一节描述了这些的结构体和它们的使用方法。

## 基本的对象类型和宏

所有的 Python 对象都在对象的内存表示的开始部分共享少量的字段。 这些字段用 `PyObject` 或 `PyVarObject` 类型来表示，这些类型又由一些宏定义，这些宏也直接或间接地用于所有其他 Python 对象的定义。

type PyObject
  属于 受限 API. （仅特定成员属于稳定 ABI。）

  所有对象类型都是此类型的扩展。 这是一个包含了 Python 将对象的指针当作对象来处理所需的信息的类型。 在一个普通的“发行”编译版中，它只包含对象的引用计数和指向对应类型对象的指针。 没有什么对象被实际声明为 `PyObject`，但每个指向 Python 对象的指针都可以被转换为 PyObject*。 对成员的访问必须通过使用 `Py_REFCNT` 和 `Py_TYPE` 宏来完成。

type PyVarObject
  属于 受限 API. （仅特定成员属于稳定 ABI。）

  这是一个添加了 `ob_size` 字段的 `PyObject` 扩展。 它仅用于具有某些 长度 标记的对象。 此类型并不经常在 Python/C API 中出现。 对成员的访问必须通过使用 `Py_REFCNT`, `Py_TYPE` 和 `Py_SIZE` 宏来完成。

PyObject_HEAD

  这是一个在声明代表无可变长度对象的新类型时所使用的宏。 PyObject_HEAD 宏被扩展为:

      PyObject ob_base;

  参见上面 `PyObject` 的文档。

PyObject_VAR_HEAD

  这是一个在声明代表每个实例具有可变长度的对象时所使用的宏。 PyObject_VAR_HEAD 宏被扩展为:

      PyVarObject ob_base;

  参见上面 `PyVarObject` 的文档。

int Py_Is(PyObject *x, PyObject *y)
  属于 稳定 ABI 自 3.10 版起.

  测试 x 是否为 y 对象，与 Python 中的 `x is y` 相同。

  在 3.10 版新加入.

int Py_IsNone(PyObject *x)
  属于 稳定 ABI 自 3.10 版起.

  测试一个对象是否为 `None` 单例，与 Python 中的 `x is None` 相同。

  在 3.10 版新加入.

int Py_IsTrue(PyObject *x)
  属于 稳定 ABI 自 3.10 版起.

  测试一个对象是否为 `True` 单例，与 Python 中的 `x is True` 相同。

  在 3.10 版新加入.

int Py_IsFalse(PyObject *x)
  属于 稳定 ABI 自 3.10 版起.

  测试一个对象是否为 `False` 单例，与 Python 中的 `x is False` 相同。

  在 3.10 版新加入.

PyTypeObject *Py_TYPE(PyObject *o)

  获取 Python 对象 o 的类型。

  返回一个 borrowed reference。

  使用 `Py_SET_TYPE()` 函数来设置一个对象类型。

  在 3.11 版的變更: `Py_TYPE()` 被改为一个内联的静态函数。 形参类型不再是 const PyObject*。

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 的类型设为 type。

  在 3.9 版新加入.

Py_ssize_t Py_REFCNT(PyObject *o)

  获取 Python 对象 o 的引用计数。

  使用 `Py_SET_REFCNT()` 函数来设置一个对象引用计数。

  在 3.11 版的變更: 形参类型不再是 const PyObject*。

  在 3.10 版的變更: `Py_REFCNT()` 被改为内联的静态函数。

void Py_SET_REFCNT(PyObject *o, Py_ssize_t refcnt)

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

  在 3.9 版新加入.

Py_ssize_t Py_SIZE(PyVarObject *o)

  获取 Python 对象 o 的大小。

  使用 `Py_SET_SIZE()` 函数来设置一个对象大小。

  在 3.11 版的變更: `Py_SIZE()` 被改为一个内联静态函数。 形参类型不再是 const PyVarObject*。

void Py_SET_SIZE(PyVarObject *o, Py_ssize_t size)

  将对象 o 的大小设为 size。

  在 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
  属于 稳定 ABI.

  用于在 C 中实现大多数 Python 可调用对象的函数类型。 该类型的函数接受两个 PyObject* 形参并返回一个这样的值。 如果返回值为 `NULL`，则将设置一个异常。 如果不为 `NULL`，则返回值将被解读为 Python 中暴露的函数的返回值。 此函数必须返回一个新的引用。

  函数的签名为:

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

type PyCFunctionWithKeywords
  属于 稳定 ABI.

  用于在 C 中实现具有 METH_VARARGS | METH_KEYWORDS 签名的 Python 可调用对象的函数类型。 函数的签名为:

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

type _PyCFunctionFast

  用于在 C 中实现具有 `METH_FASTCALL` 签名的 Python 可调用对象的函数类型。 函数的签名为:

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

type _PyCFunctionFastWithKeywords

  用于在 C 中实现具有 METH_FASTCALL | METH_KEYWORDS 签名的 Python 可调用对象的函数类型。 函数的签名为:

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

type PyCMethod

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

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

  在 3.9 版新加入.

type PyMethodDef
  属于 稳定 ABI （包括所有成员）.

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

  const char *ml_name

    方法的名称。

  PyCFunction ml_meth

    指向 C 语言实现的指针。

  int ml_flags

    指明调用应当如何构建的旗标位。

  const char *ml_doc

    指向文档字符串的内容。

`ml_meth` 是一个 C 函数指针。 该函数可以为不同类型，但它们将总是返回 PyObject*。 如果该函数不属于 `PyCFunction`，则编译器将要求在方法表中进行转换。 尽管 `PyCFunction` 将第一个参数定义为 PyObject*，但该方法的实现使用 self 对象的特定 C 类型也很常见。

`ml_flags` 字段是可以包含以下旗标的位字段。 每个旗标表示一个调用惯例或绑定惯例。

调用惯例有如下这些:

METH_VARARGS

  这是典型的调用惯例，其中方法的类型为 `PyCFunction`。 该函数接受两个 PyObject* 值。 第一个是用于方法的 self 对象；对于模块函数，它将为模块对象。 第二个形参 (常被命名为 args) 是一个代表所有参数的元组对象。 该形参通常是使用 `PyArg_ParseTuple()` 或 `PyArg_UnpackTuple()` 来处理的。

METH_KEYWORDS

  只能用于同其他旗标形成特定的组合: METH_VARARGS | METH_KEYWORDS, METH_FASTCALL | METH_KEYWORDS 和 METH_METHOD | METH_FASTCALL | METH_KEYWORDS。

METH_VARARGS | METH_KEYWORDS

  带有这些旗标的方法必须为 `PyCFunctionWithKeywords` 类型。 该函数接受三个形参: self, args, kwargs 其中 kwargs 是一个包含所有关键字参数的字典或者如果没有关键字参数则可以为 `NULL`。 这些形参通常是使用 `PyArg_ParseTupleAndKeywords()` 来处理的。

METH_FASTCALL

  快速调用惯例仅支持位置参数。 这些方法的类型为 `_PyCFunctionFast`。 第一个形参为 self，第二个形参是由表示参数的 PyObject* 值组成的数组而第三个形参是参数的数量（数组的长度）。

  在 3.7 版新加入.

  在 3.10 版的變更: `METH_FASTCALL` 现在是 稳定 ABI 的一部分。

METH_FASTCALL | METH_KEYWORDS

  `METH_FASTCALL` 的扩展也支持关键字参数，它使用类型为 `_PyCFunctionFastWithKeywords` 的方法。 关键字参数的传递方式与 vectorcall 协议 中的相同：还存在额外的第四个 PyObject* 参数，它是一个代表关键字参数名称（它将保证为字符串）的元组，或者如果没有关键字则可以为 `NULL`。 关键字参数的值存放在 args 数组中，在位置参数之后。

  在 3.7 版新加入.

METH_METHOD

  只能与其他旗标组合使用: METH_METHOD | METH_FASTCALL | METH_KEYWORDS。

METH_METHOD | METH_FASTCALL | METH_KEYWORDS

  METH_FASTCALL | METH_KEYWORDS 的扩展支持 定义式类，也就是包含相应方法的类。 定义式类可以是 `Py_TYPE(self)` 的超类。

  该方法必须为 `PyCMethod` 类型，与在 `self` 之后添加了 `defining_class` 参数的 `METH_FASTCALL | METH_KEYWORDS` 一样。

  在 3.9 版新加入.

METH_NOARGS

  如果通过 `METH_NOARGS` 旗标列出了参数则没有形参的方法无需检查是否给出了参数。 它们必须为 `PyCFunction` 类型。 第一个形参通常被命名为 self 并将持有对模块或对象实例的引用。 在所有情况下第二个形参都将为 `NULL`。

  该函数必须有 2 个形参。 由于第二个形参不会被使用，`Py_UNUSED` 可以被用来防止编译器警告。

METH_O

  具有一个单独对象参数的方法可使用 `METH_O` 旗标列出，而不必唤起 `PyArg_ParseTuple()` 并附带 `"O"` 参数。 它们的类型为 `PyCFunction`，带有 self 形参，以及代表该单独参数的 PyObject* 形参。

这两个常量不是被用来指明调用惯例而是在配合类方法使用时指明绑定。 它们不会被用于在模块上定义的函数。 对于任何给定方法这些旗标最多只会设置其中一个。

METH_CLASS

  该方法将接受类型对象而不是类型的实例作为第一个形参。 它会被用于创建 类方法，类似于使用 `classmethod()` 内置函数所创建的结果。

METH_STATIC

  该方法将接受 `NULL` 而不是类型的实例作为第一个形参。 它会被用于创建 静态方法，类似于使用 `staticmethod()` 内置函数所创建的结果。

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

METH_COEXIST

  该方法将被加载以替代现有的定义。 如果没有 METH_COEXIST，默认将跳过重复的定义。 由于槽位包装器会在方法表之前被加载，例如 当存在 sq_contains 槽位时，将会生成一个名为 `__contains__()` 的已包装方法并阻止加载同名的相应 PyCFunction。 如果定义了此旗标，PyCFunction 将被加载以替代此包装器对象并与槽位共存。 因为对 PyCFunction 的调用相比对包装器对象调用更为优化所以这是很有帮助的。

PyObject *PyCMethod_New(PyMethodDef *ml, PyObject *self, PyObject *module, PyTypeObject *cls)
  回傳值：新的參照。 属于 稳定 ABI 自 3.9 版起.

  将 ml 转为一个 Python callable 对象。 调用方必须确保 ml 的生命期长于 callable。 通常，ml 会被定义为一个静态变量。

  self 形参将在唤起时作为 `ml->ml_meth` 中 C 函数的 self 参数传入。 self 可以为 `NULL`。

  callable 对象的 `__module__` 属性可以根据给定的 module 参数来设置。 module 应为一个 Python 字符串，它将被用作函数定义所在的模块名称。 如果不可用，它将被设为 `None` 或 `NULL`。

  也參考

  `function.__module__`

  cls 形参将被作为 C 函数的 defining_class 参数传入。 如果在 `ml->ml_flags` 上设置了 `METH_METHOD` 则必须设置该形参。

  在 3.9 版新加入.

PyObject *PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module)
  回傳值：新的參照。 属于 稳定 ABI.

  等价于 `PyCMethod_New(ml, self, module, NULL)`。

PyObject *PyCFunction_New(PyMethodDef *ml, PyObject *self)
  回傳值：新的參照。 属于 稳定 ABI 自 3.4 版起.

  等价于 `PyCMethod_New(ml, self, NULL, NULL)`。

## 访问扩展类型的属性

type PyMemberDef
  属于 稳定 ABI （包括所有成员）.

  描述与某个 C 结构体成员相对应的类型的属性的结构体。 它的字段有:

  域 | C Type | 含意
  --- | --- | ---
  `name` | const char * | 成员名称
  `type` | int | C 结构体中成员的类型
  `offset` | Py_ssize_t | 成员在类型的对象结构体中所在位置的以字节表示的偏移量
  `flags` | int | 指明字段是否应为只读或可写的旗标位
  `doc` | const char * | 指向文档字符串的内容

  `type` 可以是与各种 C 类型相对应的许多 `T_` 宏中的一个。 当在 Python 中访问该成员时，它将被转换为等价的 Python 类型。

  宏名称 | C 类型
  --- | ---
  T_SHORT | short
  T_INT | int
  T_LONG | long
  T_FLOAT | float
  T_DOUBLE | double
  T_STRING | const char *
  T_OBJECT | PyObject *
  T_OBJECT_EX | PyObject *
  T_CHAR | char
  T_BYTE | char
  T_UBYTE | unsigned char
  T_UINT | unsigned int
  T_USHORT | unsigned short
  T_ULONG | unsigned long
  T_BOOL | char
  T_LONGLONG | long long
  T_ULONGLONG | unsigned long long
  T_PYSSIZET | Py_ssize_t

  `T_OBJECT` 和 `T_OBJECT_EX` 的区别在于 `T_OBJECT` 返回 `None` 表示其成员为 `NULL` 并且 `T_OBJECT_EX` 引发了 `AttributeError`。 请尝试使用 `T_OBJECT_EX` 取代 `T_OBJECT` 因为 `T_OBJECT_EX` 处理在属性上使用 `del` 语句比 `T_OBJECT` 更正确。

  `flags` 可以为 `0` 表示读写访问或 `READONLY` 表示只读访问。 使用 `T_STRING` 作为 `type` 表示 `READONLY`。 `T_STRING` 数据将被解读为 UTF-8 编码格式。 只有 `T_OBJECT` 和 `T_OBJECT_EX` 成员可以被删除。 (它们会被设为 `NULL`)。

  堆分配类型 (使用 `PyType_FromSpec()` 或类似函数创建), `PyMemberDef` 可以包含特殊成员 `__dictoffset__`, `__weaklistoffset__` 和 `__vectorcalloffset__` 的定义，对应类型对象中的 `tp_dictoffset`, `tp_weaklistoffset` 和 `tp_vectorcall_offset`。 它们必须使用 `T_PYSSIZET` 和 `READONLY` 来定义，例如:

      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)

  获取属于地址Get an attribute belonging to the object at address obj_addr 上的对象的某个属性。 该属性是以 `PyMemberDef` m 来描述的。 出错时返回 `NULL`。

int PyMember_SetOne(char *obj_addr, struct PyMemberDef *m, PyObject *o)

  将属于位于地址 obj_addr 的对象的属性设置到对象 o。 要设置的属性由 `PyMemberDef` m 描述。 成功时返回 `0` 而失败时返回负值。

type PyGetSetDef
  属于 稳定 ABI （包括所有成员）.

  用于定义针对某个类型的特征属性式的访问的结构体。 另请参阅 `PyTypeObject.tp_getset` 槽位的描述。

  域 | C Type | 含意
  --- | --- | ---
  name | const char * | 属性名称
  get | getter | 用于获取属性的 C 函数
  set | setter | 用于设置或删除属性的可选 C 函数，如果省略则属性将为只读
  doc | const char * | 可选的文档字符串
  closure | void * | optional user data pointer, providing additional data for getter and setter

  The `get` function takes one PyObject* parameter (the instance) and a user data pointer (the associated `closure`):

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

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

  `set` functions take two PyObject* parameters (the instance and the value to be set) and a user data pointer (the associated `closure`):

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

  对于属性要被删除的情况第二个形参应为 `NULL`。 成功时应返回 `0` 或在失败时返回 `-1` 并设置异常。