# 公用对象结构体

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

## 基本的对象类型和宏

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

`PyObject`

  All object types are extensions of this type. This is a type which contains the information Python needs to treat a pointer to an object as an object. In a normal "release" build, it contains only the object's reference count and a pointer to the corresponding type object. Nothing is actually declared to be a `PyObject`, but every pointer to a Python object can be cast to a `PyObject*`. Access to the members must be done by using the macros `Py_REFCNT` and `Py_TYPE`.

`PyVarObject`

  这是一个 `PyObject` 的添加了 `ob_size` 字段的扩展。 它仅用于具有某种 长度 标记的对象。 此类型并不经常在 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` 的文档。

`Py_TYPE`(o)

  This macro is used to access the `ob_type` member of a Python object. It expands to:

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

  3.9 新版功能.

`Py_REFCNT`(o)

  This macro is used to access the `ob_refcnt` member of a Python object. It expands to:

      (((PyObject*)(o))->ob_refcnt)

void `Py_SET_REFCNT`(PyObject *o, Py_ssize_t refcnt)

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

  3.9 新版功能.

`Py_SIZE`(o)

  This macro is used to access the `ob_size` member of a Python object. It expands to:

      (((PyVarObject*)(o))->ob_size)

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,

## 实现函数和方法

`PyCFunction`

  Type of the functions used to implement most Python callables in C. Functions of this type take two `PyObject*` parameters and return one such value. If the return value is `NULL`, an exception shall have been set. If not `NULL`, the return value is interpreted as the return value of the function as exposed in Python. The function must return a new reference.

  函数的签名为:

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

`PyCFunctionWithKeywords`

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

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

`_PyCFunctionFast`

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

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

`_PyCFunctionFastWithKeywords`

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

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

`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 新版功能.

`PyMethodDef`

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

  域 | C 类型 | 含意
  --- | --- | ---
  `ml_name` | const char * | 方法名
  `ml_meth` | PyCFunction | 指向 C 实现的指针
  `ml_flags` | int | flag bits indicating how the call should be constructed
  `ml_doc` | const char * | 指向文档字符串的内容

The `ml_meth` is a C function pointer. The functions may be of different types, but they always return `PyObject*`. If the function is not of the `PyCFunction`, the compiler will require a cast in the method table. Even though `PyCFunction` defines the first parameter as `PyObject*`, it is common that the method implementation uses the specific C type of the self object.

The `ml_flags` field is a bitfield which can include the following flags. The individual flags indicate either a calling convention or a binding convention.

调用惯例有如下这些:

`METH_VARARGS`

  This is the typical calling convention, where the methods have the type `PyCFunction`. The function expects two `PyObject*` values. The first one is the self object for methods; for module functions, it is the module object. The second parameter (often called args) is a tuple object representing all arguments. This parameter is typically processed using `PyArg_ParseTuple()` or `PyArg_UnpackTuple()`.

`METH_VARARGS | METH_KEYWORDS`

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

`METH_FASTCALL`

  Fast calling convention supporting only positional arguments. The methods have the type `_PyCFunctionFast`. The first parameter is self, the second parameter is a C array of `PyObject*` values indicating the arguments and the third parameter is the number of arguments (the length of the array).

  This is not part of the limited API.

  3.7 新版功能.

`METH_FASTCALL | METH_KEYWORDS`

  Extension of `METH_FASTCALL` supporting also keyword arguments, with methods of type `_PyCFunctionFastWithKeywords`. Keyword arguments are passed the same way as in the vectorcall protocol: there is an additional fourth `PyObject*` parameter which is a tuple representing the names of the keyword arguments (which are guaranteed to be strings) or possibly `NULL` if there are no keywords. The values of the keyword arguments are stored in the args array, after the positional arguments.

  This is not part of the limited API.

  3.7 新版功能.

`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`。

`METH_O`

  Methods with a single object argument can be listed with the `METH_O` flag, instead of invoking `PyArg_ParseTuple()` with a `"O"` argument. They have the type `PyCFunction`, with the self parameter, and a `PyObject*` parameter representing the single argument.

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

`METH_CLASS`

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

`METH_STATIC`

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

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

`METH_COEXIST`

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

## 访问扩展类型的属性

`PyMemberDef`

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

  域 | C 类型 | 含意
  --- | --- | ---
  `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 | 长整型
  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` 而失败时返回负值。

`PyGetSetDef`

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

  域 | C 类型 | 含意
  --- | --- | ---
  name | const char * | 属性名称
  get | getter | 用于获取属性的 C 函数
  set | setter | 用于设置或删除属性的可选 C 函数，如果省略则属性将为只读
  doc | const char * | 可选的文档字符串
  closure | void * | 可选的函数指针，为 getter 和 setter 提供附加数据

  The `get` function takes one `PyObject*` parameter (the instance) and a function 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 function pointer (the associated `closure`):

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

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