常用物件結構

Python 中定義物件型別時會用到大量的結構體。本節將描述這些結構體以及它們是如何使用的。

基本物件型別和宏

所有 Python 物件最終在記憶體中的物件表示的開頭共享少量欄位。這些欄位由 PyObjectPyVarObject 型別表示,這些型別又由一些宏的擴充套件定義,這些宏直接或間接地用於定義所有其他 Python 物件。其他宏可以在 引用計數 下找到。

type PyObject
屬於 有限 API 的一部分。(只有部分成員是穩定的 ABI 的一部分。)

所有物件型別都是此型別的擴充套件。這是一種包含 Python 將物件指標視為物件所需資訊的型別。在正常的 “release” 版本中,它僅包含物件的引用計數和指向相應型別物件的指標。實際上沒有宣告為 PyObject,但每個指向 Python 物件的指標都可以轉換為 PyObject*。對成員的訪問必須使用宏 Py_REFCNTPy_TYPE 完成。

type PyVarObject
屬於 有限 API 的一部分。(只有部分成員是穩定的 ABI 的一部分。)

這是 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 的文件。

int Py_Is(PyObject *x, PyObject *y)
自 3.10 版本起,屬於 穩定 ABI 的一部分。

測試 x 物件是否為 y 物件,與 Python 中的 x is y 相同。

3.10 版本中新增。

int Py_IsNone(PyObject *x)
自 3.10 版本起,屬於 穩定 ABI 的一部分。

測試物件是否為 None 單例,與 Python 中的 x is None 相同。

3.10 版本中新增。

int Py_IsTrue(PyObject *x)
自 3.10 版本起,屬於 穩定 ABI 的一部分。

測試物件是否為 True 單例,與 Python 中的 x is True 相同。

3.10 版本中新增。

int Py_IsFalse(PyObject *x)
自 3.10 版本起,屬於 穩定 ABI 的一部分。

測試物件是否為 False 單例,與 Python 中的 x is False 相同。

3.10 版本中新增。

PyTypeObject *Py_TYPE(PyObject *o)
返回值:借用引用。

獲取 Python 物件 o 的型別。

返回一個 借用引用

使用 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_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
自 3.13 版本以來,屬於 穩定 ABI 的一部分。

用於在 C 中實現具有簽名 METH_FASTCALL 的 Python 可呼叫物件的函式的型別。函式簽名是

PyObject *PyCFunctionFast(PyObject *self,
                          PyObject *const *args,
                          Py_ssize_t nargs);
type PyCFunctionFastWithKeywords
自 3.13 版本以來,屬於 穩定 ABI 的一部分。

用於在 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_KEYWORDSMETH_FASTCALL | METH_KEYWORDSMETH_METHOD | METH_FASTCALL | METH_KEYWORDS

METH_VARARGS | METH_KEYWORDS

具有這些標誌的方法必須是 PyCFunctionWithKeywords 型別。該函式期望三個引數:selfargskwargs,其中 kwargs 是所有關鍵字引數的字典,如果沒有任何關鍵字引數,則可能為 NULL。通常使用 PyArg_ParseTupleAndKeywords() 來處理這些引數。

METH_FASTCALL

僅支援位置引數的快速呼叫約定。這些方法具有 PyCFunctionFast 型別。第一個引數是 self,第二個引數是一個 C 的 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 型別,與 METH_FASTCALL | METH_KEYWORDS 相同,但 在 self 之後添加了 defining_class 引數。

3.9 版本中新增。

METH_NOARGS

如果使用 METH_NOARGS 標誌列出,則無引數的方法不需要檢查是否提供了引數。它們需要是 PyCFunction 型別。第一個引數通常命名為 self,並將儲存對模組或物件例項的引用。在所有情況下,第二個引數將為 NULL

該函式必須有 2 個引數。由於第二個引數未使用,可以使用 Py_UNUSED 來防止編譯器警告。

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 的呼叫比包裝物件呼叫更最佳化。

PyObject *PyCMethod_New(PyMethodDef *ml, PyObject *self, PyObject *module, PyTypeObject *cls)
返回值:新引用。 自 3.9 版本以來,是 穩定 ABI 的一部分。

ml 轉換為 Python 可呼叫 物件。呼叫者必須確保 ml 的生存時間長於 可呼叫 物件。通常,ml 被定義為靜態變數。

呼叫時,self 引數將作為 self 引數傳遞給 ml->ml_meth 中的 C 函式。self 可以是 NULL

可以使用給定的 module 引數設定 可呼叫 物件的 __module__ 屬性。module 應該是一個 Python 字串,它將用作定義該函式的模組的名稱。如果不可用,可以將其設定為 NoneNULL

另請參閱

function.__module__

cls 引數將作為 defining_class 引數傳遞給 C 函式。如果 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)
返回值:新引用。 自 3.4 版本以來,是 穩定 ABI 的一部分。

等效於 PyCMethod_New(ml, self, NULL, NULL)

訪問擴充套件型別的屬性

type PyMemberDef
屬於 穩定 ABI 的一部分(包括所有成員)。

描述型別屬性的結構,該屬性對應於 C 結構成員。在定義類時,將這些結構的以 NULL 結尾的陣列放入 tp_members 槽中。

其欄位依次為

const char *name

成員的名稱。NULL 值標記 PyMemberDef[] 陣列的末尾。

該字串應該是靜態的,不會對其進行復制。

int type

C 結構體中成員的型別。有關可能的值,請參閱成員型別

Py_ssize_t offset

成員在型別物件的結構體中所處的位元組偏移量。

int flags

成員標誌中的零個或多個標誌,使用按位或組合。

const char *doc

文件字串,或 NULL。該字串應該是靜態的,不會對其進行復制。通常,它使用 PyDoc_STR 定義。

預設情況下(當flags0 時),成員允許讀寫訪問。對於只讀訪問,請使用 Py_READONLY 標誌。某些型別,如 Py_T_STRING,表示 Py_READONLY。只有 Py_T_OBJECT_EX (和舊式的 T_OBJECT)成員可以被刪除。

對於堆分配的型別(使用 PyType_FromSpec() 或類似方法建立),PyMemberDef 可能包含特殊成員 "__vectorcalloffset__" 的定義,它對應於型別物件中的 tp_vectorcall_offset。這些必須使用 Py_T_PYSSIZETPy_READONLY 定義,例如

static PyMemberDef spam_type_members[] = {
    {"__vectorcalloffset__", Py_T_PYSSIZET,
     offsetof(Spam_object, vectorcall), Py_READONLY},
    {NULL}  /* Sentinel */
};

(你可能需要 #include <stddef.h> 來使用 offsetof()。)

可以使用 "__dictoffset__""__weaklistoffset__" 成員類似地定義舊式的偏移量 tp_dictoffsettp_weaklistoffset,但強烈建議擴充套件使用 Py_TPFLAGS_MANAGED_DICTPy_TPFLAGS_MANAGED_WEAKREF

在 3.12 版本中更改: PyMemberDef 總是可用。之前,它需要包含 "structmember.h"

PyObject *PyMember_GetOne(const char *obj_addr, struct PyMemberDef *m)
屬於 穩定 ABI 的一部分。

獲取位於地址 obj_addr 的物件的屬性。該屬性由 PyMemberDef m 描述。發生錯誤時返回 NULL

在 3.12 版本中更改: PyMember_GetOne 總是可用。之前,它需要包含 "structmember.h"

int PyMember_SetOne(char *obj_addr, struct PyMemberDef *m, PyObject *o)
屬於 穩定 ABI 的一部分。

將位於地址 obj_addr 的物件的屬性設定為物件 o。要設定的屬性由 PyMemberDef m 描述。如果成功則返回 0,失敗則返回負值。

在 3.12 版本中更改: PyMember_SetOne 總是可用。之前,它需要包含 "structmember.h"

成員標誌

以下標誌可與 PyMemberDef.flags 一起使用

Py_READONLY

不可寫。

Py_AUDIT_READ

在讀取之前發出一個 object.__getattr__ 審計事件

Py_RELATIVE_OFFSET

表示此 PyMemberDef 條目的 offset 指示從子類特定的資料開始的偏移量,而不是從 PyObject 開始的偏移量。

當使用負的 basicsize 建立類時,只能作為 Py_tp_members slot 的一部分使用。在這種情況下,它是強制性的。

此標誌僅在 PyType_Slot 中使用。在類建立期間設定 tp_members 時,Python 會清除它並將 PyMemberDef.offset 設定為從 PyObject 結構開始的偏移量。

在 3.10 版本中更改: #include "structmember.h" 可用的 RESTRICTEDREAD_RESTRICTEDWRITE_RESTRICTED 宏已被棄用。READ_RESTRICTEDRESTRICTED 等同於 Py_AUDIT_READWRITE_RESTRICTED 不執行任何操作。

在 3.12 版本中更改: READONLY 宏已重新命名為 Py_READONLYPY_AUDIT_READ 宏已使用 Py_ 字首重新命名。現在,新的名稱始終可用。以前,這些需要 #include "structmember.h"。該標頭檔案仍然可用,它提供了舊的名稱。

成員型別

PyMemberDef.type 可以是以下對應於各種 C 型別的宏之一。當在 Python 中訪問成員時,它將被轉換為等效的 Python 型別。當從 Python 設定時,它將轉換回 C 型別。如果不可能,則會引發諸如 TypeErrorValueError 之類的異常。

除非標記為 (D),否則無法使用例如 deldelattr() 刪除以此方式定義的屬性。

宏名稱

C 型別

Python 型別

Py_T_BYTE

char

int

Py_T_SHORT

short

int

Py_T_INT

int

int

Py_T_LONG

long

int

Py_T_LONGLONG

long long

int

Py_T_UBYTE

unsigned char

int

Py_T_UINT

unsigned int

int

Py_T_USHORT

unsigned short

int

Py_T_ULONG

unsigned long

int

Py_T_ULONGLONG

unsigned long long

int

Py_T_PYSSIZET

Py_ssize_t

int

Py_T_FLOAT

float

float

Py_T_DOUBLE

double

float

Py_T_BOOL

char (表示為 0 或 1)

bool

Py_T_STRING

const char* (*)

str (只讀)

Py_T_STRING_INPLACE

const char[] (*)

str (只讀)

Py_T_CHAR

char (0-127)

str (**)

Py_T_OBJECT_EX

PyObject*

object (D)

(*): 以空字元結尾、UTF8 編碼的 C 字串。對於 Py_T_STRING,C 表示形式是指標;對於 Py_T_STRING_INPLACE,字串直接儲存在結構中。

(**): 長度為 1 的字串。僅接受 ASCII 字元。

(只讀): 意味著 Py_READONLY

(D): 可以刪除,在這種情況下,指標設定為 NULL。讀取 NULL 指標會引發 AttributeError

3.12 版本新增: 在之前的版本中,宏只能透過 #include "structmember.h" 使用,並且沒有 Py_ 字首(例如,T_INT)。標頭檔案仍然可用,並且包含舊名稱,以及以下已棄用的型別

T_OBJECT

類似於 Py_T_OBJECT_EX,但 NULL 會轉換為 None。這會導致 Python 中出現令人驚訝的行為:刪除屬性實際上會將其設定為 None

T_NONE

始終為 None。必須與 Py_READONLY 一起使用。

定義 Getters 和 Setters

type PyGetSetDef
屬於 穩定 ABI 的一部分(包括所有成員)。

用於為型別定義類似屬性的訪問的結構。另請參閱 PyTypeObject.tp_getset 插槽的描述。

const char *name

屬性名稱

getter get

用於獲取屬性的 C 函式。

setter set

用於設定或刪除屬性的可選 C 函式。如果為 NULL,則該屬性為只讀。

const char *doc

可選的文件字串

void *closure

可選的使用者資料指標,為 getter 和 setter 提供額外資料。

typedef PyObject *(*getter)(PyObject*, void*)
屬於 穩定 ABI 的一部分。

get 函式接受一個 PyObject* 引數(例項)和一個使用者資料指標(關聯的 closure)。

成功時應返回新引用,失敗時應返回 NULL 並設定異常。

typedef int (*setter)(PyObject*, PyObject*, void*)
屬於 穩定 ABI 的一部分。

set 函式接受兩個 PyObject* 引數(例項和要設定的值)和一個使用者資料指標(關聯的 closure)。

如果應刪除該屬性,則第二個引數為 NULL。成功時應返回 0,失敗時應返回 -1 並設定異常。