型別物件

也許 Python 物件系統最重要的結構之一是定義新型別的結構:PyTypeObject 結構。型別物件可以使用任何 PyObject_*PyType_* 函式來處理,但對於大多數 Python 應用程式來說,它們沒有提供太多有趣的東西。這些物件是物件行為方式的基礎,因此對於直譯器本身以及任何實現新型別的擴充套件模組來說,它們都非常重要。

與大多數標準型別相比,型別物件相當大。大小的原因是每個型別物件都儲存大量值,主要是 C 函式指標,每個指標都實現型別功能的一小部分。本節將詳細檢查型別物件的欄位。這些欄位將按照它們在結構中出現的順序進行描述。

除了以下快速參考外,示例 部分還提供了 PyTypeObject 的含義和用法的快速瞭解。

快速參考

“tp 插槽”

PyTypeObject 插槽 [1]

型別

特殊方法/屬性

資訊 [2]

O

T

D

I

<R> tp_name

const char *

__name__

X

X

tp_basicsize

Py_ssize_t

X

X

X

tp_itemsize

Py_ssize_t

X

X

tp_dealloc

解構函式

X

X

X

tp_vectorcall_offset

Py_ssize_t

X

X

(tp_getattr)

getattrfunc

__getattribute__, __getattr__

G

(tp_setattr)

setattrfunc

__setattr__, __delattr__

G

tp_as_async

PyAsyncMethods *

子插槽

%

tp_repr

reprfunc

__repr__

X

X

X

tp_as_number

PyNumberMethods *

子插槽

%

tp_as_sequence

PySequenceMethods *

子插槽

%

tp_as_mapping

PyMappingMethods *

子插槽

%

tp_hash

hashfunc

__hash__

X

G

tp_call

ternaryfunc

__call__

X

X

tp_str

reprfunc

__str__

X

X

tp_getattro

getattrofunc

__getattribute__, __getattr__

X

X

G

tp_setattro

setattrofunc

__setattr__, __delattr__

X

X

G

tp_as_buffer

PyBufferProcs *

%

tp_flags

unsigned long

X

X

?

tp_doc

const char *

__doc__

X

X

tp_traverse

traverseproc

X

G

tp_clear

inquiry

X

G

tp_richcompare

richcmpfunc

__lt__, __le__, __eq__, __ne__, __gt__, __ge__

X

G

(tp_weaklistoffset)

Py_ssize_t

X

?

tp_iter

getiterfunc

__iter__

X

tp_iternext

iternextfunc

__next__

X

tp_methods

PyMethodDef []

X

X

tp_members

PyMemberDef []

X

tp_getset

PyGetSetDef []

X

X

tp_base

PyTypeObject *

__base__

X

tp_dict

PyObject *

__dict__

?

tp_descr_get

descrgetfunc

__get__

X

tp_descr_set

descrsetfunc

__set__, __delete__

X

(tp_dictoffset)

Py_ssize_t

X

?

tp_init

initproc

__init__

X

X

X

tp_alloc

allocfunc

X

?

?

tp_new

newfunc

__new__

X

X

?

?

tp_free

freefunc

X

X

?

?

tp_is_gc

inquiry

X

X

<tp_bases>

PyObject *

__bases__

~

<tp_mro>

PyObject *

__mro__

~

[tp_cache]

PyObject *

[tp_subclasses]

void *

__subclasses__

[tp_weaklist]

PyObject *

(tp_del)

解構函式

[tp_version_tag]

unsigned int

tp_finalize

解構函式

__del__

X

tp_vectorcall

vectorcallfunc

[tp_watched]

unsigned char

子插槽

插槽

型別

特殊方法

am_await

unaryfunc

__await__

am_aiter

unaryfunc

__aiter__

am_anext

unaryfunc

__anext__

am_send

sendfunc

nb_add

binaryfunc

__add__ __radd__

nb_inplace_add

binaryfunc

__iadd__

nb_subtract

binaryfunc

__sub__ __rsub__

nb_inplace_subtract

binaryfunc

__isub__

nb_multiply

binaryfunc

__mul__ __rmul__

nb_inplace_multiply

binaryfunc

__imul__

nb_remainder

binaryfunc

__mod__ __rmod__

nb_inplace_remainder

binaryfunc

__imod__

nb_divmod

binaryfunc

__divmod__ __rdivmod__

nb_power

ternaryfunc

__pow__ __rpow__

nb_inplace_power

ternaryfunc

__ipow__

nb_negative

unaryfunc

__neg__

nb_positive

unaryfunc

__pos__

nb_absolute

unaryfunc

__abs__

nb_bool

inquiry

__bool__

nb_invert

unaryfunc

__invert__

nb_lshift

binaryfunc

__lshift__ __rlshift__

nb_inplace_lshift

binaryfunc

__ilshift__

nb_rshift

binaryfunc

__rshift__ __rrshift__

nb_inplace_rshift

binaryfunc

__irshift__

nb_and

binaryfunc

__and__ __rand__

nb_inplace_and

binaryfunc

__iand__

nb_xor

binaryfunc

__xor__ __rxor__

nb_inplace_xor

binaryfunc

__ixor__

nb_or

binaryfunc

__or__ __ror__

nb_inplace_or

binaryfunc

__ior__

nb_int

unaryfunc

__int__

nb_reserved

void *

nb_float

unaryfunc

__float__

nb_floor_divide

binaryfunc

__floordiv__

nb_inplace_floor_divide

binaryfunc

__ifloordiv__

nb_true_divide

binaryfunc

__truediv__

nb_inplace_true_divide

binaryfunc

__itruediv__

nb_index

unaryfunc

__index__

nb_matrix_multiply

binaryfunc

__matmul__ __rmatmul__

nb_inplace_matrix_multiply

binaryfunc

__imatmul__

mp_length

lenfunc

__len__

mp_subscript

binaryfunc

__getitem__

mp_ass_subscript

objobjargproc

__setitem__, __delitem__

sq_length

lenfunc

__len__

sq_concat

binaryfunc

__add__

sq_repeat

ssizeargfunc

__mul__

sq_item

ssizeargfunc

__getitem__

sq_ass_item

ssizeobjargproc

__setitem__ __delitem__

sq_contains

objobjproc

__contains__

sq_inplace_concat

binaryfunc

__iadd__

sq_inplace_repeat

ssizeargfunc

__imul__

bf_getbuffer

getbufferproc()

bf_releasebuffer

releasebufferproc()

插槽 typedef

typedef

引數型別

返回型別

allocfunc

PyObject *

解構函式

PyObject *

void

freefunc

void *

void

traverseproc

void *

int

newfunc

PyObject *

initproc

int

reprfunc

PyObject *

PyObject *

getattrfunc

const char *

PyObject *

setattrfunc

const char *

int

getattrofunc

PyObject *

setattrofunc

int

descrgetfunc

PyObject *

descrsetfunc

int

hashfunc

PyObject *

Py_hash_t

richcmpfunc

int

PyObject *

getiterfunc

PyObject *

PyObject *

iternextfunc

PyObject *

PyObject *

lenfunc

PyObject *

Py_ssize_t

getbufferproc

int

releasebufferproc

void

inquiry

PyObject *

int

unaryfunc

PyObject *

binaryfunc

PyObject *

ternaryfunc

PyObject *

ssizeargfunc

PyObject *

ssizeobjargproc

int

objobjproc

int

objobjargproc

int

有關更多詳細資訊,請參見下面的插槽型別 typedef

PyTypeObject 定義

PyTypeObject 的結構定義可以在 Include/object.h 中找到。為了方便參考,這裡重複了其中找到的定義

typedef struct _typeobject {
    PyObject_VAR_HEAD
    const char *tp_name; /* For printing, in format "<module>.<name>" */
    Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */

    /* Methods to implement standard operations */

    destructor tp_dealloc;
    Py_ssize_t tp_vectorcall_offset;
    getattrfunc tp_getattr;
    setattrfunc tp_setattr;
    PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2)
                                    or tp_reserved (Python 3) */
    reprfunc tp_repr;

    /* Method suites for standard classes */

    PyNumberMethods *tp_as_number;
    PySequenceMethods *tp_as_sequence;
    PyMappingMethods *tp_as_mapping;

    /* More standard operations (here for binary compatibility) */

    hashfunc tp_hash;
    ternaryfunc tp_call;
    reprfunc tp_str;
    getattrofunc tp_getattro;
    setattrofunc tp_setattro;

    /* Functions to access object as input/output buffer */
    PyBufferProcs *tp_as_buffer;

    /* Flags to define presence of optional/expanded features */
    unsigned long tp_flags;

    const char *tp_doc; /* Documentation string */

    /* Assigned meaning in release 2.0 */
    /* call function for all accessible objects */
    traverseproc tp_traverse;

    /* delete references to contained objects */
    inquiry tp_clear;

    /* Assigned meaning in release 2.1 */
    /* rich comparisons */
    richcmpfunc tp_richcompare;

    /* weak reference enabler */
    Py_ssize_t tp_weaklistoffset;

    /* Iterators */
    getiterfunc tp_iter;
    iternextfunc tp_iternext;

    /* Attribute descriptor and subclassing stuff */
    struct PyMethodDef *tp_methods;
    struct PyMemberDef *tp_members;
    struct PyGetSetDef *tp_getset;
    // Strong reference on a heap type, borrowed reference on a static type
    struct _typeobject *tp_base;
    PyObject *tp_dict;
    descrgetfunc tp_descr_get;
    descrsetfunc tp_descr_set;
    Py_ssize_t tp_dictoffset;
    initproc tp_init;
    allocfunc tp_alloc;
    newfunc tp_new;
    freefunc tp_free; /* Low-level free-memory routine */
    inquiry tp_is_gc; /* For PyObject_IS_GC */
    PyObject *tp_bases;
    PyObject *tp_mro; /* method resolution order */
    PyObject *tp_cache;
    PyObject *tp_subclasses;
    PyObject *tp_weaklist;
    destructor tp_del;

    /* Type attribute cache version tag. Added in version 2.6 */
    unsigned int tp_version_tag;

    destructor tp_finalize;
    vectorcallfunc tp_vectorcall;

    /* bitset of which type-watchers care about this type */
    unsigned char tp_watched;
} PyTypeObject;

PyObject 插槽

型別物件結構擴充套件了 PyVarObject 結構。ob_size 欄位用於動態型別(由 type_new() 建立,通常從類語句中呼叫)。請注意,PyType_Type(元型別)初始化 tp_itemsize,這意味著它的例項(即型別物件)必須具有 ob_size 欄位。

Py_ssize_t PyObject.ob_refcnt
屬於 穩定 ABI 的一部分。

這是型別物件的引用計數,由 PyObject_HEAD_INIT 宏初始化為 1。請注意,對於靜態分配的型別物件,型別的例項(其 ob_type 指回該型別的物件)計入引用。但是,對於動態分配的型別物件,例項確實計入引用。

繼承

此欄位不會被子型別繼承。

PyTypeObject *PyObject.ob_type
屬於 穩定 ABI 的一部分。

這是型別的型別,換句話說,是它的元型別。它由 PyObject_HEAD_INIT 宏的引數初始化,其值通常應為 &PyType_Type。但是,對於必須在 Windows (至少) 上可用的動態載入的擴充套件模組,編譯器會抱怨這不是一個有效的初始化程式。因此,約定是將 NULL 傳遞給 PyObject_HEAD_INIT 宏,並在模組初始化函式的開始處顯式初始化此欄位,然後再執行任何其他操作。這通常像這樣完成:

Foo_Type.ob_type = &PyType_Type;

應該在建立型別的任何例項之前完成此操作。PyType_Ready() 檢查 ob_type 是否為 NULL,如果是,則將其初始化為基類的 ob_type 欄位。PyType_Ready() 如果此欄位非零,則不會更改此欄位。

繼承

此欄位被子型別繼承。

PyVarObject 槽

Py_ssize_t PyVarObject.ob_size
屬於 穩定 ABI 的一部分。

對於靜態分配的型別物件,此欄位應初始化為零。對於動態分配的型別物件,此欄位具有特殊的內部含義。

繼承

此欄位不會被子型別繼承。

PyTypeObject 槽

每個槽都有一個描述繼承的部分。如果 PyType_Ready() 可以在欄位設定為 NULL 時設定一個值,則還會有一個“預設”部分。(請注意,在 PyBaseObject_TypePyType_Type 上設定的許多欄位實際上充當預設值。)

const char *PyTypeObject.tp_name

指向一個以 NULL 結尾的字串的指標,其中包含型別的名稱。對於作為模組全域性變數訪問的型別,該字串應該是完整的模組名稱,後跟一個點,後跟型別名稱;對於內建型別,它應該只是型別名稱。如果模組是包的子模組,則完整的包名稱是完整模組名稱的一部分。例如,在包 P 中的子包 Q 中的模組 M 中定義的名為 T 的型別應具有 tp_name 初始化器 "P.Q.M.T"

對於動態分配的型別物件,這應該只是型別名稱,模組名稱顯式儲存在型別字典中,作為鍵 '__module__' 的值。

對於靜態分配的型別物件tp_name 欄位應包含一個點。最後一個點之前的所有內容都可以作為 __module__ 屬性訪問,最後一個點之後的所有內容都可以作為 __name__ 屬性訪問。

如果不存在點,則整個 tp_name 欄位可以作為 __name__ 屬性訪問,並且 __module__ 屬性是未定義的(除非如上所述在字典中顯式設定)。這意味著您的型別將無法 pickle。此外,它不會列在用 pydoc 建立的模組文件中。

此欄位不能為 NULL。它是 PyTypeObject() 中唯一必需的欄位(可能除了 tp_itemsize 之外)。

繼承

此欄位不會被子型別繼承。

Py_ssize_t PyTypeObject.tp_basicsize
Py_ssize_t PyTypeObject.tp_itemsize

這些欄位允許計算型別例項的大小(以位元組為單位)。

有兩種型別的型別:具有固定長度例項的型別具有零 tp_itemsize 欄位,具有可變長度例項的型別具有非零 tp_itemsize 欄位。對於具有固定長度例項的型別,所有例項都具有相同的大小,在 tp_basicsize 中給出。

對於具有可變長度例項的型別,例項必須具有 ob_size 欄位,並且例項大小為 tp_basicsize 加上 N 乘以 tp_itemsize,其中 N 是物件的“長度”。 N 的值通常儲存在例項的 ob_size 欄位中。但也存在例外:例如,整數使用負的 ob_size 來表示負數,而 N 在那裡是 abs(ob_size)。此外,例項佈局中存在 ob_size 欄位並不意味著例項結構是可變長度的(例如,列表型別的結構具有固定長度的例項,但這些例項具有有意義的 ob_size 欄位)。

基本大小包括由宏 PyObject_HEADPyObject_VAR_HEAD(無論使用哪個來宣告例項結構)宣告的例項中的欄位,這反過來包括 _ob_prev_ob_next 欄位(如果它們存在)。這意味著獲取 tp_basicsize 的初始值的唯一正確方法是對用於宣告例項佈局的結構使用 sizeof 運算子。基本大小不包括 GC 標頭大小。

關於對齊的說明:如果可變項需要特定的對齊方式,則應由 tp_basicsize 的值來處理。示例:假設一個型別實現了一個 double 陣列。tp_itemsizesizeof(double)。程式設計師有責任確保 tp_basicsizesizeof(double) 的倍數(假設這是 double 的對齊要求)。

對於任何具有可變長度例項的型別,此欄位不能為 NULL

繼承

這些欄位由子型別單獨繼承。如果基型別具有非零的 tp_itemsize,通常在子型別中將 tp_itemsize 設定為不同的非零值是不安全的(儘管這取決於基型別的實現)。

destructor PyTypeObject.tp_dealloc

指向例項解構函式的指標。除非型別保證其例項永遠不會被釋放(如單例 NoneEllipsis 的情況),否則必須定義此函式。函式簽名是

void tp_dealloc(PyObject *self);

當新的引用計數為零時,解構函式由 Py_DECREF()Py_XDECREF() 宏呼叫。此時,例項仍然存在,但沒有對它的引用。解構函式應釋放例項擁有的所有引用,釋放例項擁有的所有記憶體緩衝區(使用與用於分配緩衝區的分配函式相對應的釋放函式),並呼叫型別的 tp_free 函式。如果型別不可子型別化(沒有設定 Py_TPFLAGS_BASETYPE 標誌位),則可以直接呼叫物件釋放器,而不是透過 tp_free。物件釋放器應該是用於分配例項的釋放器;如果例項是使用 PyObject_NewPyObject_NewVar 分配的,則通常為 PyObject_Del();如果例項是使用 PyObject_GC_NewPyObject_GC_NewVar 分配的,則為 PyObject_GC_Del()

如果該型別支援垃圾回收(已設定 Py_TPFLAGS_HAVE_GC 標誌位),則解構函式應在清除任何成員欄位之前呼叫 PyObject_GC_UnTrack()

static void foo_dealloc(foo_object *self) {
    PyObject_GC_UnTrack(self);
    Py_CLEAR(self->ref);
    Py_TYPE(self)->tp_free((PyObject *)self);
}

最後,如果該型別是堆分配的 (Py_TPFLAGS_HEAPTYPE),則釋放器應在呼叫型別釋放器之後(透過 Py_DECREF())釋放對其型別物件擁有的引用。為了避免懸空指標,推薦的實現方法是

static void foo_dealloc(foo_object *self) {
    PyTypeObject *tp = Py_TYPE(self);
    // free references and buffers here
    tp->tp_free(self);
    Py_DECREF(tp);
}

警告

在垃圾回收的 Python 中,tp_dealloc 可以從任何 Python 執行緒呼叫,而不僅僅是建立物件的執行緒(如果物件成為引用計數迴圈的一部分,則該迴圈可能由任何執行緒上的垃圾回收收集)。對於 Python API 呼叫來說,這不是問題,因為呼叫 tp_dealloc 的執行緒將擁有全域性直譯器鎖 (GIL)。但是,如果正在銷燬的物件反過來又銷燬了來自其他 C 或 C++ 庫的物件,則應注意確保在呼叫 tp_dealloc 的執行緒上銷燬這些物件不會違反庫的任何假設。

繼承

此欄位被子型別繼承。

Py_ssize_t PyTypeObject.tp_vectorcall_offset

一個可選的偏移量,指向實現使用 vectorcall 協議 呼叫物件的每個例項的函式,這是更簡單的 tp_call 的更高效替代方案。

只有當設定了 Py_TPFLAGS_HAVE_VECTORCALL 標誌時,才使用此欄位。如果設定了該標誌,則該值必須是一個正整數,其中包含例項中 vectorcallfunc 指標的偏移量。

vectorcallfunc 指標可以為 NULL,在這種情況下,例項的行為就好像沒有設定 Py_TPFLAGS_HAVE_VECTORCALL 一樣:呼叫例項將回退到 tp_call

任何設定 Py_TPFLAGS_HAVE_VECTORCALL 的類還必須設定 tp_call,並確保其行為與 vectorcallfunc 函式一致。這可以透過將 tp_call 設定為 PyVectorcall_Call() 來完成。

在 3.8 版本中更改: 在 3.8 版本之前,此槽名為 tp_print。在 Python 2.x 中,它用於列印到檔案。在 Python 3.0 到 3.7 中,它未使用。

在 3.12 版本中更改: 在 3.12 版本之前,不建議 可變堆型別 實現 vectorcall 協議。當用戶在 Python 程式碼中設定 __call__ 時,只會更新 tp_call,這可能會導致它與 vectorcall 函式不一致。自 3.12 版本以來,設定 __call__ 將透過清除 Py_TPFLAGS_HAVE_VECTORCALL 標誌來停用 vectorcall 最佳化。

繼承

此欄位始終被繼承。但是,Py_TPFLAGS_HAVE_VECTORCALL 標誌並不總是被繼承。如果未設定該標誌,則子類將不會使用 vectorcall,除非顯式呼叫 PyVectorcall_Call()

getattrfunc PyTypeObject.tp_getattr

一個可選的指向獲取屬性字串函式的指標。

此欄位已棄用。當它被定義時,它應該指向一個功能與 tp_getattro 函式相同,但使用 C 字串而不是 Python 字串物件來給出屬性名稱的函式。

繼承

組: tp_getattr, tp_getattro

此欄位與 tp_getattro 一起由子型別繼承:當子型別的 tp_getattrtp_getattro 都為 NULL 時,子型別會從其基型別繼承 tp_getattrtp_getattro

setattrfunc PyTypeObject.tp_setattr

一個可選的指向設定和刪除屬性的函式的指標。

此欄位已棄用。當它被定義時,它應該指向一個功能與 tp_setattro 函式相同,但使用 C 字串而不是 Python 字串物件來給出屬性名稱的函式。

繼承

組: tp_setattr, tp_setattro

此欄位與 tp_setattro 一起由子型別繼承:當子型別的 tp_setattrtp_setattro 都為 NULL 時,子型別會從其基型別繼承 tp_setattrtp_setattro

PyAsyncMethods *PyTypeObject.tp_as_async

指向一個附加結構的指標,該結構僅包含與在 C 級別實現 可等待非同步迭代器 協議的物件相關的欄位。有關詳細資訊,請參閱 非同步物件結構

3.5 版本新增: 以前稱為 tp_comparetp_reserved

繼承

tp_as_async 欄位不被繼承,但其中包含的欄位會被單獨繼承。

reprfunc PyTypeObject.tp_repr

一個可選的指向實現內建函式 repr() 的函式的指標。

簽名與 PyObject_Repr() 的相同

PyObject *tp_repr(PyObject *self);

該函式必須返回一個字串或一個 Unicode 物件。理想情況下,此函式應返回一個字串,該字串在傳遞給 eval() 時,在給定合適的環境下,會返回一個具有相同值的物件。如果這不可行,它應該返回一個以 '<' 開頭並以 '>' 結尾的字串,從中可以推斷出物件的型別和值。

繼承

此欄位被子型別繼承。

預設

當此欄位未設定時,將返回 <%s object at %p> 形式的字串,其中 %s 替換為型別名稱,%p 替換為物件的記憶體地址。

PyNumberMethods *PyTypeObject.tp_as_number

指向一個附加結構的指標,該結構僅包含與實現數字協議的物件相關的欄位。這些欄位在 數字物件結構 中進行了說明。

繼承

tp_as_number 欄位不被繼承,但其中包含的欄位會被單獨繼承。

PySequenceMethods *PyTypeObject.tp_as_sequence

指向一個附加結構的指標,該結構僅包含與實現序列協議的物件相關的欄位。這些欄位在 序列物件結構 中進行了說明。

繼承

tp_as_sequence 欄位不被繼承,但其中包含的欄位會被單獨繼承。

PyMappingMethods *PyTypeObject.tp_as_mapping

指向一個附加結構的指標,該結構僅包含與實現對映協議的物件相關的欄位。這些欄位在 對映物件結構 中進行了說明。

繼承

tp_as_mapping 欄位不被繼承,但其中包含的欄位會被單獨繼承。

hashfunc PyTypeObject.tp_hash

一個可選的函式指標,用於實現內建函式 hash()

其簽名與 PyObject_Hash() 相同。

Py_hash_t tp_hash(PyObject *);

-1 不應作為正常返回值返回;當計算雜湊值時發生錯誤時,該函式應設定一個異常並返回 -1

當此欄位未設定( tp_richcompare 未設定)時,嘗試獲取物件的雜湊值會引發 TypeError。 這與將其設定為 PyObject_HashNotImplemented() 相同。

此欄位可以顯式設定為 PyObject_HashNotImplemented(),以阻止從父型別繼承雜湊方法。這被解釋為在 Python 級別等效於 __hash__ = None,從而使 isinstance(o, collections.Hashable) 正確返回 False。請注意,反之亦然 - 在 Python 級別的類上設定 __hash__ = None 將導致 tp_hash 插槽設定為 PyObject_HashNotImplemented()

繼承

組: tp_hashtp_richcompare

此欄位與 tp_richcompare 一起被子型別繼承:當子型別的 tp_richcomparetp_hash 都為 NULL 時,子型別將同時繼承 tp_richcomparetp_hash

預設

PyBaseObject_Type 使用 PyObject_GenericHash()

ternaryfunc PyTypeObject.tp_call

一個可選的函式指標,用於實現呼叫物件。如果物件不可呼叫,則應為 NULL。其簽名與 PyObject_Call() 相同。

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

繼承

此欄位被子型別繼承。

reprfunc PyTypeObject.tp_str

一個可選的函式指標,用於實現內建操作 str()。(請注意,現在 str 是一種型別,而 str() 呼叫該型別的建構函式。此建構函式呼叫 PyObject_Str() 來完成實際工作,而 PyObject_Str() 將呼叫此處理程式。)

其簽名與 PyObject_Str() 相同。

PyObject *tp_str(PyObject *self);

該函式必須返回字串或 Unicode 物件。 它應該是物件的“友好”字串表示形式,因為這是 print() 函式等將使用的表示形式。

繼承

此欄位被子型別繼承。

預設

當此欄位未設定時,將呼叫 PyObject_Repr() 返回字串表示形式。

getattrofunc PyTypeObject.tp_getattro

一個可選的獲取屬性函式指標。

其簽名與 PyObject_GetAttr() 相同。

PyObject *tp_getattro(PyObject *self, PyObject *attr);

通常將其設定為 PyObject_GenericGetAttr() 很方便,它實現了查詢物件屬性的正常方法。

繼承

組: tp_getattr, tp_getattro

此欄位與 tp_getattr 一起被子型別繼承:當子型別的 tp_getattrtp_getattro 都為 NULL 時,子型別將從其基型別同時繼承 tp_getattrtp_getattro

預設

PyBaseObject_Type 使用 PyObject_GenericGetAttr()

setattrofunc PyTypeObject.tp_setattro

一個可選的指向設定和刪除屬性的函式的指標。

其簽名與 PyObject_SetAttr() 相同。

int tp_setattro(PyObject *self, PyObject *attr, PyObject *value);

此外,必須支援將value 設定為 NULL 來刪除屬性。 通常,將其設定為 PyObject_GenericSetAttr() 很方便,它實現了設定物件屬性的正常方法。

繼承

組: tp_setattr, tp_setattro

此欄位與 tp_setattr 一起被子型別繼承:當子型別的 tp_setattrtp_setattro 都為 NULL 時,子型別將從其基型別同時繼承 tp_setattrtp_setattro

預設

PyBaseObject_Type 使用 PyObject_GenericSetAttr()

PyBufferProcs *PyTypeObject.tp_as_buffer

指向一個附加結構的指標,該結構包含僅與實現緩衝區介面的物件相關的欄位。 這些欄位在緩衝區物件結構中進行了文件說明。

繼承

tp_as_buffer欄位不被繼承,但其中包含的欄位會被單獨繼承。

unsigned long PyTypeObject.tp_flags

此欄位是各種標誌的位掩碼。 一些標誌指示某些情況下的變體語義;另一些標誌用於指示型別物件中的某些欄位(或透過tp_as_numbertp_as_sequencetp_as_mappingtp_as_buffer引用的擴充套件結構中的欄位),這些欄位在歷史上並非總是存在,而是有效的;如果此類標誌位被清除,則必須禁止訪問其保護的型別欄位,並且必須將其視為具有零值或NULL值。

繼承

此欄位的繼承很複雜。 大多數標誌位是單獨繼承的,即如果基型別設定了標誌位,則子型別將繼承此標誌位。 如果繼承了擴充套件結構,則與擴充套件結構有關的標誌位將被嚴格繼承,即基型別的標誌位值將與指向擴充套件結構的指標一起復制到子型別中。Py_TPFLAGS_HAVE_GC標誌位與tp_traversetp_clear欄位一起繼承,即,如果子型別中的Py_TPFLAGS_HAVE_GC標誌位被清除,並且子型別中的tp_traversetp_clear欄位存在並且具有NULL值。 .. XXX 大多數標誌位真的是單獨繼承的嗎?

預設

PyBaseObject_Type使用Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE

位掩碼

當前定義了以下位掩碼;可以使用|運算子將它們或運算在一起,以形成tp_flags欄位的值。宏PyType_HasFeature() 接受一個型別和一個標誌值, tpf,並檢查tp->tp_flags & f是否非零。

Py_TPFLAGS_HEAPTYPE

當型別物件本身在堆上分配時,例如,使用PyType_FromSpec()動態建立的型別時,會設定此位。在這種情況下,其例項的ob_type欄位被視為對該型別的引用,並且在建立新例項時,該型別物件被 INCREF,並在例項被銷燬時被 DECREF(這不適用於子型別的例項;只有例項的 ob_type 引用的型別才會 INCREF 或 DECREF)。堆型別也應該支援垃圾回收,因為它們可以與自己的模組物件形成引用迴圈。

繼承

???

Py_TPFLAGS_BASETYPE

當該型別可以用作另一個型別的基型別時,會設定此位。 如果此位被清除,則該型別不能被子型別化(類似於 Java 中的“final”類)。

繼承

???

Py_TPFLAGS_READY

當型別物件已由PyType_Ready()完全初始化時,會設定此位。

繼承

???

Py_TPFLAGS_READYING

PyType_Ready()正在初始化型別物件時,會設定此位。

繼承

???

Py_TPFLAGS_HAVE_GC

當物件支援垃圾回收時,會設定此位。如果設定了此位,則必須使用PyObject_GC_New建立例項,並使用PyObject_GC_Del()銷燬例項。 更多資訊請參見支援迴圈垃圾回收部分。此位還意味著型別物件中存在與 GC 相關的欄位tp_traversetp_clear

繼承

組:Py_TPFLAGS_HAVE_GCtp_traversetp_clear

Py_TPFLAGS_HAVE_GC標誌位與tp_traversetp_clear欄位一起繼承,即,如果子型別中的Py_TPFLAGS_HAVE_GC標誌位被清除,並且子型別中的tp_traversetp_clear欄位存在並且具有NULL值。

Py_TPFLAGS_DEFAULT

這是一個位掩碼,其中包含與型別物件及其擴充套件結構中某些欄位的存在相關的所有位。目前,它包括以下位:Py_TPFLAGS_HAVE_STACKLESS_EXTENSION

繼承

???

Py_TPFLAGS_METHOD_DESCRIPTOR

此位表示物件的行為類似於未繫結的方法。

如果為type(meth)設定了此標誌,則

  • meth.__get__(obj, cls)(*args, **kwds) (其中 obj 不是 None) 必須等效於 meth(obj, *args, **kwds)

  • meth.__get__(None, cls)(*args, **kwds) 必須等價於 meth(*args, **kwds)

此標誌為典型的如 obj.meth() 的方法呼叫啟用最佳化:它避免為 obj.meth 建立臨時的“繫結方法”物件。

3.8 版本新增。

繼承

此標誌永遠不會被未設定 Py_TPFLAGS_IMMUTABLETYPE 標誌的型別繼承。對於擴充套件型別,當繼承 tp_descr_get 時,它會被繼承。

Py_TPFLAGS_MANAGED_DICT

此位表示該類的例項具有 ~object.__dict__ 屬性,並且字典的空間由虛擬機器管理。

如果設定了此標誌,則還應設定 Py_TPFLAGS_HAVE_GC

型別遍歷函式必須呼叫 PyObject_VisitManagedDict(),並且其清除函式必須呼叫 PyObject_ClearManagedDict()

3.12 版本新增。

繼承

除非在超類中設定了 tp_dictoffset 欄位,否則此標誌會被繼承。

Py_TPFLAGS_MANAGED_WEAKREF

此位表示該類的例項應該是可弱引用的。

3.12 版本新增。

繼承

除非在超類中設定了 tp_weaklistoffset 欄位,否則此標誌會被繼承。

Py_TPFLAGS_ITEMS_AT_END

僅可用於可變大小的型別,即具有非零 tp_itemsize 的型別。

表示此型別的例項的可變大小部分位於例項記憶體區域的末尾,偏移量為 Py_TYPE(obj)->tp_basicsize(在每個子類中可能不同)。

設定此標誌時,請確保所有超類都使用此記憶體佈局,或者都不是可變大小的。Python 不會對此進行檢查。

3.12 版本新增。

繼承

此標誌會被繼承。

Py_TPFLAGS_LONG_SUBCLASS
Py_TPFLAGS_LIST_SUBCLASS
Py_TPFLAGS_TUPLE_SUBCLASS
Py_TPFLAGS_BYTES_SUBCLASS
Py_TPFLAGS_UNICODE_SUBCLASS
Py_TPFLAGS_DICT_SUBCLASS
Py_TPFLAGS_BASE_EXC_SUBCLASS
Py_TPFLAGS_TYPE_SUBCLASS

這些標誌被諸如 PyLong_Check() 之類的函式用來快速確定型別是否是內建型別的子類;這種特定的檢查比像 PyObject_IsInstance() 這樣的通用檢查更快。從內建型別繼承的自定義型別應適當設定其 tp_flags,否則與此類型別互動的程式碼將根據使用的檢查型別而表現不同。

Py_TPFLAGS_HAVE_FINALIZE

當型別結構中存在 tp_finalize 插槽時,將設定此位。

3.4 版本新增。

3.8 版本起已棄用: 此標誌不再必要,因為直譯器假定型別結構中始終存在 tp_finalize 插槽。

Py_TPFLAGS_HAVE_VECTORCALL

當類實現 vectorcall 協議時,將設定此位。 有關詳細資訊,請參見 tp_vectorcall_offset

繼承

如果也繼承了 tp_call,則會繼承此位。

3.9 版本新增。

在 3.12 版本中變更: 當重新分配類的 __call__() 方法時,現在會從類中刪除此標誌。

現在,可變類可以繼承此標誌。

Py_TPFLAGS_IMMUTABLETYPE

對於不可變的型別物件,會設定此位:不能設定或刪除型別屬性。

PyType_Ready() 會自動將此標誌應用於靜態型別

繼承

此標誌不會被繼承。

3.10 版本新增。

Py_TPFLAGS_DISALLOW_INSTANTIATION

禁止建立該型別的例項:將 tp_new 設定為 NULL,並且不在型別字典中建立 __new__ 鍵。

該標誌必須在建立型別之前設定,而不是之後。例如,它必須在對該型別呼叫 PyType_Ready() 之前設定。

如果 tp_base 為 NULL 或 &PyBaseObject_Type 並且 tp_new 為 NULL,則會在靜態型別上自動設定該標誌。

繼承

此標誌不會被繼承。但是,除非子類提供非 NULL 的 tp_new(這隻能透過 C API 實現),否則子類將不可例項化。

注意

要禁止直接例項化類,但允許例項化其子類(例如,對於抽象基類),請不要使用此標誌。而是使 tp_new 僅對子類成功。

3.10 版本新增。

Py_TPFLAGS_MAPPING

此位表示該類的例項在用作 match 塊的主題時,可以匹配對映模式。 當註冊或子類化 collections.abc.Mapping 時,會自動設定它,當註冊 collections.abc.Sequence 時,會取消設定它。

注意

Py_TPFLAGS_MAPPINGPy_TPFLAGS_SEQUENCE 是互斥的;同時啟用這兩個標誌是錯誤的。

繼承

此標誌會被尚未設定 Py_TPFLAGS_SEQUENCE 的型別繼承。

另請參閱

PEP 634 – 結構化模式匹配:規範

3.10 版本新增。

Py_TPFLAGS_SEQUENCE

此位表示當該類的例項用作 match 程式碼塊的主題時,可以匹配序列模式。當註冊或子類化 collections.abc.Sequence 時會自動設定此位,而當註冊 collections.abc.Mapping 時會取消設定此位。

注意

Py_TPFLAGS_MAPPINGPy_TPFLAGS_SEQUENCE 是互斥的;同時啟用這兩個標誌是錯誤的。

繼承

此標誌會被尚未設定 Py_TPFLAGS_MAPPING 的型別繼承。

另請參閱

PEP 634 – 結構化模式匹配:規範

3.10 版本新增。

Py_TPFLAGS_VALID_VERSION_TAG

內部使用。請勿設定或取消設定此標誌。要指示類已更改,請呼叫 PyType_Modified()

警告

此標誌存在於標頭檔案中,但未使用。它將在 CPython 的未來版本中刪除。

const char *PyTypeObject.tp_doc

一個可選的指向以 NUL 結尾的 C 字串的指標,它給出了此型別物件的文件字串。這會作為型別及其型別例項上的 __doc__ 屬性公開。

繼承

此欄位不會被子型別繼承。

traverseproc PyTypeObject.tp_traverse

一個可選的指向垃圾收集器的遍歷函式的指標。僅當設定了 Py_TPFLAGS_HAVE_GC 標誌位時才使用。其簽名為

int tp_traverse(PyObject *self, visitproc visit, void *arg);

關於 Python 垃圾回收方案的更多資訊,請參見 支援迴圈垃圾回收 部分。

tp_traverse 指標被垃圾收集器用來檢測引用迴圈。tp_traverse 函式的典型實現只是在其擁有的例項成員中,對每個屬於 Python 物件的成員呼叫 Py_VISIT()。例如,以下是來自 _thread 擴充套件模組中的函式 local_traverse()

static int
local_traverse(localobject *self, visitproc visit, void *arg)
{
    Py_VISIT(self->args);
    Py_VISIT(self->kw);
    Py_VISIT(self->dict);
    return 0;
}

請注意,Py_VISIT() 僅在那些可以參與引用迴圈的成員上呼叫。儘管還有一個 self->key 成員,但它只能是 NULL 或 Python 字串,因此不能成為引用迴圈的一部分。

另一方面,即使您知道某個成員永遠不會成為迴圈的一部分,作為除錯輔助手段,您可能仍然希望訪問它,以便 gc 模組的 get_referents() 函式會包含它。

堆型別(Py_TPFLAGS_HEAPTYPE)必須使用

Py_VISIT(Py_TYPE(self));

這僅在 Python 3.9 中需要。為了支援 Python 3.8 及更早的版本,此行必須是條件性的

#if PY_VERSION_HEX >= 0x03090000
    Py_VISIT(Py_TYPE(self));
#endif

如果在 tp_flags 欄位中設定了 Py_TPFLAGS_MANAGED_DICT 位,則 traverse 函式必須像這樣呼叫 PyObject_VisitManagedDict()

PyObject_VisitManagedDict((PyObject*)self, visit, arg);

警告

在實現 tp_traverse 時,只需要訪問例項擁有(透過對它們具有強引用)的成員。例如,如果一個物件透過 tp_weaklist 插槽支援弱引用,則支援連結串列的指標(tp_weaklist 指向的指標)必須被訪問,因為該例項不直接擁有對其自身的弱引用(弱引用列表是為了支援弱引用機制,但例項對其中的元素沒有強引用,因為即使例項仍然存在,也允許刪除它們)。

請注意,Py_VISIT() 要求 local_traverse() 的 *visit* 和 *arg* 引數具有這些特定的名稱;不要隨意命名它們。

堆分配型別 的例項保持對其型別的引用。因此,它們的遍歷函式必須訪問 Py_TYPE(self),或者透過呼叫另一個堆分配型別(例如堆分配的超類)的 tp_traverse 來委派此責任。如果它們不這樣做,則型別物件可能無法被垃圾回收。

在 3.9 版本中更改: 堆分配型別應在 tp_traverse 中訪問 Py_TYPE(self)。在早期版本的 Python 中,由於 錯誤 40217,這樣做可能會導致子類崩潰。

繼承

組:Py_TPFLAGS_HAVE_GCtp_traversetp_clear

此欄位與 tp_clearPy_TPFLAGS_HAVE_GC 標誌位一起被子型別繼承:如果子型別中所有位都為零,則標誌位、tp_traversetp_clear 都從基型別繼承。

inquiry PyTypeObject.tp_clear

一個可選的指向垃圾收集器的清除函式的指標。僅當設定了 Py_TPFLAGS_HAVE_GC 標誌位時才使用。其簽名為

int tp_clear(PyObject *);

tp_clear 成員函式用於在垃圾收集器檢測到的迴圈垃圾中打破引用迴圈。綜合來看,系統中所有的 tp_clear 函式必須組合起來以打破所有引用迴圈。這很微妙,如果有任何疑問,請提供 tp_clear 函式。例如,元組型別不實現 tp_clear 函式,因為可以證明沒有任何引用迴圈可以完全由元組組成。因此,其他型別的 tp_clear 函式必須足以打破任何包含元組的迴圈。這並不是顯而易見的,而且很少有很好的理由避免實現 tp_clear

tp_clear 的實現應該刪除例項對其可能是 Python 物件的成員的引用,並將指向這些成員的指標設定為 NULL,如下例所示

static int
local_clear(localobject *self)
{
    Py_CLEAR(self->key);
    Py_CLEAR(self->args);
    Py_CLEAR(self->kw);
    Py_CLEAR(self->dict);
    return 0;
}

應該使用 Py_CLEAR() 宏,因為清除引用很微妙:在將指向包含物件的指標設定為 NULL 之後,才能釋放(透過 Py_DECREF())對包含物件的引用。這是因為釋放引用可能會導致包含的物件變成垃圾,從而觸發一系列回收活動,其中可能包括呼叫任意 Python 程式碼(由於與包含物件關聯的終結器或弱引用回撥)。如果此類程式碼有可能再次引用 self,那麼重要的是,此時指向包含物件的指標為 NULL,以便 self 知道不能再使用包含的物件。Py_CLEAR() 宏以安全的順序執行操作。

如果在 tp_flags 欄位中設定了 Py_TPFLAGS_MANAGED_DICT 位,則遍歷函式必須像這樣呼叫 PyObject_ClearManagedDict()

PyObject_ClearManagedDict((PyObject*)self);

請注意,tp_clear 並非總是在例項被釋放之前呼叫。例如,當引用計數足以確定不再使用物件時,不會涉及迴圈垃圾收集器,而是直接呼叫 tp_dealloc

由於 tp_clear 函式的目標是打破引用迴圈,因此沒有必要清除像 Python 字串或 Python 整數這樣的包含物件,因為它們不能參與引用迴圈。另一方面,清除所有包含的 Python 物件可能很方便,並編寫型別的 tp_dealloc 函式來呼叫 tp_clear

關於 Python 垃圾回收方案的更多資訊,請參見 支援迴圈垃圾回收 部分。

繼承

組:Py_TPFLAGS_HAVE_GCtp_traversetp_clear

此欄位與 tp_traversePy_TPFLAGS_HAVE_GC 標誌位一起被子型別繼承:如果子型別中的標誌位、tp_traversetp_clear 都為零,則它們都從基型別繼承。

richcmpfunc PyTypeObject.tp_richcompare

指向富比較函式的可選指標,其簽名如下

PyObject *tp_richcompare(PyObject *self, PyObject *other, int op);

保證第一個引數是由 PyTypeObject 定義的型別的例項。

該函式應返回比較的結果(通常為 Py_TruePy_False)。如果比較未定義,則必須返回 Py_NotImplemented;如果發生其他錯誤,則必須返回 NULL 並設定異常條件。

定義以下常量以用作 tp_richcomparePyObject_RichCompare() 的第三個引數

常量

比較

Py_LT

<

Py_LE

<=

Py_EQ

==

Py_NE

!=

Py_GT

>

Py_GE

>=

定義以下宏來簡化富比較函式的編寫

Py_RETURN_RICHCOMPARE(VAL_A, VAL_B, op)

根據比較的結果,從函式返回 Py_TruePy_False。VAL_A 和 VAL_B 必須可以透過 C 比較運算子進行排序(例如,它們可以是 C 整數或浮點數)。第三個引數指定請求的操作,與 PyObject_RichCompare() 相同。

返回的值是一個新的 強引用

如果發生錯誤,則設定異常並從函式返回 NULL

在 3.7 版本中新增。

繼承

組: tp_hashtp_richcompare

此欄位與 tp_hash 一起由子型別繼承:當子型別的 tp_richcomparetp_hash 都為 NULL 時,子型別將繼承 tp_richcomparetp_hash

預設

PyBaseObject_Type 提供了一個 tp_richcompare 實現,可以被繼承。但是,如果只定義了 tp_hash,則即使繼承的函式也不會被使用,並且該型別的例項將無法參與任何比較。

Py_ssize_t PyTypeObject.tp_weaklistoffset

雖然仍然支援此欄位,但如果可能,應使用 Py_TPFLAGS_MANAGED_WEAKREF

如果此型別的例項可弱引用,則此欄位大於零,幷包含例項結構中弱引用列表頭的偏移量(忽略 GC 標頭,如果存在);此偏移量由 PyObject_ClearWeakRefs()PyWeakref_* 函式使用。例項結構需要包含一個型別為 PyObject* 的欄位,該欄位初始化為 NULL

不要將此欄位與 tp_weaklist 混淆;後者是型別物件本身的弱引用的列表頭。

同時設定 Py_TPFLAGS_MANAGED_WEAKREF 位和 tp_weaklistoffset 是錯誤的。

繼承

此欄位由子型別繼承,但請參閱下面列出的規則。子型別可以覆蓋此偏移量;這意味著子型別使用與基型別不同的弱引用列表頭。由於列表頭始終透過 tp_weaklistoffset 找到,因此這應該不是問題。

預設

如果在 tp_flags 欄位中設定了 Py_TPFLAGS_MANAGED_WEAKREF 位,則 tp_weaklistoffset 將被設定為負值,以指示使用此欄位是不安全的。

getiterfunc PyTypeObject.tp_iter

一個可選的函式指標,該函式返回物件的迭代器。它的存在通常表示此型別的例項是可迭代的(儘管序列可能在沒有此函式的情況下也是可迭代的)。

此函式具有與PyObject_GetIter()相同的簽名。

PyObject *tp_iter(PyObject *self);

繼承

此欄位被子型別繼承。

iternextfunc PyTypeObject.tp_iternext

一個可選的函式指標,該函式返回迭代器中的下一個專案。簽名是

PyObject *tp_iternext(PyObject *self);

當迭代器耗盡時,它必須返回NULL;可能設定也可能不設定StopIteration異常。當發生其他錯誤時,它也必須返回NULL。它的存在表明此型別的例項是迭代器。

迭代器型別還應該定義tp_iter函式,並且該函式應該返回迭代器例項本身(而不是新的迭代器例項)。

此函式具有與PyIter_Next()相同的簽名。

繼承

此欄位被子型別繼承。

struct PyMethodDef *PyTypeObject.tp_methods

一個可選的指標,指向一個以NULL結尾的靜態PyMethodDef結構陣列,宣告此型別的常規方法。

對於陣列中的每個條目,都會將一個條目新增到型別的字典(請參閱下面的tp_dict),其中包含一個方法描述符。

繼承

此欄位不會被子型別繼承(方法是透過不同的機制繼承的)。

struct PyMemberDef *PyTypeObject.tp_members

一個可選的指標,指向一個以NULL結尾的靜態PyMemberDef結構陣列,宣告此型別例項的常規資料成員(欄位或槽)。

對於陣列中的每個條目,都會將一個條目新增到型別的字典(請參閱下面的tp_dict),其中包含一個成員描述符。

繼承

此欄位不會被子型別繼承(成員是透過不同的機制繼承的)。

struct PyGetSetDef *PyTypeObject.tp_getset

一個可選的指標,指向一個以NULL結尾的靜態PyGetSetDef結構陣列,宣告此型別例項的計算屬性。

對於陣列中的每個條目,都會將一個條目新增到型別的字典(請參閱下面的tp_dict),其中包含一個 getset 描述符。

繼承

此欄位不會被子型別繼承(計算屬性是透過不同的機制繼承的)。

PyTypeObject *PyTypeObject.tp_base

一個可選的指標,指向從中繼承型別屬性的基型別。在此級別,僅支援單繼承;多重繼承需要透過呼叫元型別來動態建立型別物件。

注意

槽初始化受全域性變數初始化規則的約束。C99 要求初始化程式為“地址常量”。函式指示符(如PyType_GenericNew())隱式轉換為指標,是有效的 C99 地址常量。

但是,應用於非靜態變數(如PyBaseObject_Type)的一元“&”運算子不一定產生地址常量。編譯器可能支援此操作(gcc 支援),而 MSVC 不支援。在這方面,兩個編譯器都嚴格符合標準。

因此,應在擴充套件模組的 init 函式中設定tp_base

繼承

此欄位不會被子型別繼承(顯然)。

預設

此欄位的預設值為&PyBaseObject_Type(Python 程式設計師將其稱為型別object)。

PyObject *PyTypeObject.tp_dict

型別的字典由PyType_Ready()儲存在此處。

在呼叫 PyType_Ready 之前,此欄位通常應初始化為NULL;它也可以初始化為包含型別初始屬性的字典。一旦PyType_Ready()初始化了型別,則只有當它們不對應於過載操作(如__add__())時,才可以將型別的額外屬性新增到此字典中。一旦完成型別的初始化,此欄位應被視為只讀。

某些型別可能不會將它們的字典儲存在此槽中。使用PyType_GetDict()檢索任意型別的字典。

3.12 版本中的更改: 內部細節:對於靜態內建型別,這始終為NULL。相反,此類型別的字典儲存在PyInterpreterState上。使用PyType_GetDict()獲取任意型別的字典。

繼承

此欄位不會被子型別繼承(儘管此處定義的屬性是透過不同的機制繼承的)。

預設

如果此欄位為NULL,則PyType_Ready()將為其分配一個新字典。

警告

使用PyDict_SetItem()或以其他方式透過字典 C-API 修改tp_dict是不安全的。

descrgetfunc PyTypeObject.tp_descr_get

指向“描述符獲取”函式的可選指標。

函式簽名是

PyObject * tp_descr_get(PyObject *self, PyObject *obj, PyObject *type);

繼承

此欄位被子型別繼承。

descrsetfunc PyTypeObject.tp_descr_set

一個可選的函式指標,用於設定和刪除描述符的值。

函式簽名是

int tp_descr_set(PyObject *self, PyObject *obj, PyObject *value);

value 引數設定為 NULL 以刪除值。

繼承

此欄位被子型別繼承。

Py_ssize_t PyTypeObject.tp_dictoffset

雖然仍然支援此欄位,但如果可能,應使用 Py_TPFLAGS_MANAGED_DICT

如果此型別的例項具有包含例項變數的字典,則此欄位為非零值,幷包含該型別例項中例項變數字典的偏移量;此偏移量由 PyObject_GenericGetAttr() 使用。

不要將此欄位與 tp_dict 混淆;那是型別物件本身屬性的字典。

該值指定字典相對於例項結構起始位置的偏移量。

tp_dictoffset 應被視為只寫。要獲取指向字典的指標,請呼叫 PyObject_GenericGetDict()。呼叫 PyObject_GenericGetDict() 可能需要為字典分配記憶體,因此在訪問物件上的屬性時,呼叫 PyObject_GetAttr() 可能更有效率。

同時設定 Py_TPFLAGS_MANAGED_WEAKREF 位和 tp_dictoffset 是錯誤的。

繼承

此欄位由子型別繼承。子型別不應覆蓋此偏移量;如果 C 程式碼嘗試在前一個偏移量處訪問字典,這樣做可能不安全。為了正確支援繼承,請使用 Py_TPFLAGS_MANAGED_DICT

預設

此槽沒有預設值。對於靜態型別,如果該欄位為 NULL,則不會為例項建立 __dict__

如果 Py_TPFLAGS_MANAGED_DICT 位在 tp_flags 欄位中設定,則 tp_dictoffset 將設定為 -1,以指示使用此欄位是不安全的。

initproc PyTypeObject.tp_init

指向例項初始化函式的可選指標。

此函式對應於類的 __init__() 方法。與 __init__() 類似,可以在不呼叫 __init__() 的情況下建立例項,並且可以透過再次呼叫其 __init__() 方法來重新初始化例項。

函式簽名是

int tp_init(PyObject *self, PyObject *args, PyObject *kwds);

self 引數是要初始化的例項;argskwds 引數表示對 __init__() 呼叫的位置引數和關鍵字引數。

如果 tp_init 函式不為 NULL,則在透過呼叫其型別正常建立例項時,在該型別的 tp_new 函式返回該型別的例項之後呼叫。如果 tp_new 函式返回不是原始型別的子型別的其他型別的例項,則不呼叫 tp_init 函式;如果 tp_new 返回原始型別的子型別的例項,則呼叫該子型別的 tp_init

成功時返回 0,錯誤時返回 -1 並設定異常。

繼承

此欄位被子型別繼承。

預設

對於靜態型別,此欄位沒有預設值。

allocfunc PyTypeObject.tp_alloc

指向例項分配函式的可選指標。

函式簽名是

PyObject *tp_alloc(PyTypeObject *self, Py_ssize_t nitems);

繼承

此欄位由靜態子型別繼承,但不由動態子型別(由 class 語句建立的子型別)繼承。

預設

對於動態子型別,此欄位始終設定為 PyType_GenericAlloc(),以強制執行標準堆分配策略。

對於靜態子型別,PyBaseObject_Type 使用 PyType_GenericAlloc()。這是所有靜態定義型別的推薦值。

newfunc PyTypeObject.tp_new

指向例項建立函式的可選指標。

函式簽名是

PyObject *tp_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds);

subtype 引數是要建立的物件的型別;argskwds 引數表示對該型別呼叫的位置引數和關鍵字引數。請注意,subtype 不必等於呼叫其 tp_new 函式的型別;它可能是該型別的子型別(但不是不相關的型別)。

tp_new 函式應呼叫 subtype->tp_alloc(subtype, nitems) 來為物件分配空間,然後僅進行絕對必要的進一步初始化。可以安全地忽略或重複的初始化應放在 tp_init 處理程式中。一個好的經驗法則是,對於不可變型別,所有初始化都應在 tp_new 中進行,而對於可變型別,大多數初始化應推遲到 tp_init 中進行。

設定 Py_TPFLAGS_DISALLOW_INSTANTIATION 標誌以禁止在 Python 中建立該型別的例項。

繼承

此欄位由子型別繼承,但 靜態型別tp_baseNULL&PyBaseObject_Type 的情況除外,它們不繼承此欄位。

預設

對於靜態型別,此欄位沒有預設值。這意味著如果該槽定義為 NULL,則不能呼叫該型別來建立新例項;大概有其他方式可以建立例項,例如工廠函式。

freefunc PyTypeObject.tp_free

指向例項釋放函式的可選指標。其簽名為

void tp_free(void *self);

與此簽名相容的初始化程式是 PyObject_Free()

繼承

此欄位由靜態子型別繼承,但不由動態子型別(由 class 語句建立的子型別)繼承

預設

在動態子型別中,此欄位設定為一個合適的釋放器,以便與 PyType_GenericAlloc() 以及 Py_TPFLAGS_HAVE_GC 標誌位的取值相匹配。

對於靜態子型別,PyBaseObject_Type 使用 PyObject_Del()

inquiry PyTypeObject.tp_is_gc

一個可選的函式指標,由垃圾回收器呼叫。

垃圾回收器需要知道一個特定的物件是否是可回收的。通常,檢視物件的型別 tp_flags 欄位並檢查 Py_TPFLAGS_HAVE_GC 標誌位就足夠了。但是,某些型別具有靜態和動態分配的例項的混合,並且靜態分配的例項是不可回收的。此類型別應定義此函式;對於可回收的例項,它應返回 1,對於不可回收的例項,則返回 0。其簽名是

int tp_is_gc(PyObject *self);

(唯一的例子是型別本身。元型別 PyType_Type 定義了此函式來區分靜態分配的型別和動態分配的型別。)

繼承

此欄位被子型別繼承。

預設

此槽沒有預設值。如果此欄位為 NULL,則使用 Py_TPFLAGS_HAVE_GC 作為功能等效項。

PyObject *PyTypeObject.tp_bases

基型別的元組。

此欄位應設定為 NULL 並視為只讀。當型別 初始化 時,Python 將填充它。

對於動態建立的類,可以使用 Py_tp_bases 來代替 PyType_FromSpecWithBases()bases 引數。首選引數形式。

警告

多重繼承對於靜態定義的型別效果不佳。如果將 tp_bases 設定為元組,Python 不會引發錯誤,但是某些槽將僅從第一個基類繼承。

繼承

此欄位不被繼承。

PyObject *PyTypeObject.tp_mro

包含擴充套件的基型別集的元組,從型別本身開始,以 object 結束,按照方法解析順序排列。

此欄位應設定為 NULL 並視為只讀。當型別 初始化 時,Python 將填充它。

繼承

此欄位不被繼承;它由 PyType_Ready() 重新計算。

PyObject *PyTypeObject.tp_cache

未使用。僅供內部使用。

繼承

此欄位不被繼承。

void *PyTypeObject.tp_subclasses

子類的集合。僅供內部使用。可能是一個無效的指標。

要獲取子類的列表,請呼叫 Python 方法 __subclasses__()

在 3.12 版本中變更: 對於某些型別,此欄位不儲存有效的 PyObject*。該型別已更改為 void* 以指示這一點。

繼承

此欄位不被繼承。

PyObject *PyTypeObject.tp_weaklist

弱引用列表頭,用於對此型別物件的弱引用。不被繼承。僅供內部使用。

在 3.12 版本中變更:內部細節:對於靜態內建型別,即使添加了弱引用,這也始終為 NULL。相反,每個弱引用都儲存在 PyInterpreterState 上。使用公共 C-API 或內部 _PyObject_GET_WEAKREFS_LISTPTR() 宏以避免區分。

繼承

此欄位不被繼承。

destructor PyTypeObject.tp_del

此欄位已棄用。請改用 tp_finalize

unsigned int PyTypeObject.tp_version_tag

用於索引到方法快取中。僅供內部使用。

繼承

此欄位不被繼承。

destructor PyTypeObject.tp_finalize

一個指向例項終結函式的可選指標。其簽名是

void tp_finalize(PyObject *self);

如果設定了 tp_finalize,則直譯器在終結例項時會呼叫它一次。它要麼從垃圾回收器呼叫(如果例項是孤立引用迴圈的一部分),要麼在物件被釋放之前呼叫。無論哪種方式,都保證在嘗試打破引用迴圈之前呼叫它,從而確保它找到處於正常狀態的物件。

tp_finalize 不應改變當前的異常狀態;因此,編寫非平凡終結器的推薦方法是

static void
local_finalize(PyObject *self)
{
    PyObject *error_type, *error_value, *error_traceback;

    /* Save the current exception, if any. */
    PyErr_Fetch(&error_type, &error_value, &error_traceback);

    /* ... */

    /* Restore the saved exception. */
    PyErr_Restore(error_type, error_value, error_traceback);
}

繼承

此欄位被子型別繼承。

3.4 版本新增。

在 3.8 版本中變更:在 3.8 版本之前,必須設定 Py_TPFLAGS_HAVE_FINALIZE 標誌位才能使用此欄位。現在不再需要這樣做。

另請參閱

“安全物件終結”(PEP 442

vectorcallfunc PyTypeObject.tp_vectorcall

用於此型別物件呼叫的向量呼叫函式。換句話說,它用於為 type.__call__ 實現 向量呼叫。如果 tp_vectorcallNULL,則使用 __new__()__init__() 的預設呼叫實現。

繼承

此欄位永遠不會被繼承。

3.9 版本中新增:(該欄位自 3.8 版本起存在,但僅自 3.9 版本起使用)

unsigned char PyTypeObject.tp_watched

內部的。請勿使用。

3.12 版本新增。

靜態型別

傳統上,C 程式碼中定義的型別是靜態的,也就是說,一個靜態的 PyTypeObject 結構體直接在程式碼中定義,並使用 PyType_Ready() 進行初始化。

這導致型別相對於 Python 中定義的型別受到限制

  • 靜態型別僅限於一個基類,即它們不能使用多重繼承。

  • 靜態型別物件(但不一定是它們的例項)是不可變的。無法從 Python 新增或修改型別物件的屬性。

  • 靜態型別物件在 子直譯器 之間共享,因此它們不應包含任何特定於子直譯器的狀態。

此外,由於 PyTypeObject 僅作為不透明結構體是 有限 API 的一部分,因此任何使用靜態型別的擴充套件模組都必須針對特定的 Python 小版本進行編譯。

堆型別

除了 靜態型別 之外,另一種選擇是堆分配型別,或簡稱為堆型別,它與 Python 的 class 語句建立的類非常相似。堆型別設定了 Py_TPFLAGS_HEAPTYPE 標誌。

這是透過填充 PyType_Spec 結構體並呼叫 PyType_FromSpec()PyType_FromSpecWithBases()PyType_FromModuleAndSpec(),或 PyType_FromMetaclass() 來完成的。

數值物件結構體

type PyNumberMethods

此結構體儲存物件用於實現數字協議的函式的指標。每個函式都由數字協議部分中記錄的類似名稱的函式使用。

以下是結構體定義

typedef struct {
     binaryfunc nb_add;
     binaryfunc nb_subtract;
     binaryfunc nb_multiply;
     binaryfunc nb_remainder;
     binaryfunc nb_divmod;
     ternaryfunc nb_power;
     unaryfunc nb_negative;
     unaryfunc nb_positive;
     unaryfunc nb_absolute;
     inquiry nb_bool;
     unaryfunc nb_invert;
     binaryfunc nb_lshift;
     binaryfunc nb_rshift;
     binaryfunc nb_and;
     binaryfunc nb_xor;
     binaryfunc nb_or;
     unaryfunc nb_int;
     void *nb_reserved;
     unaryfunc nb_float;

     binaryfunc nb_inplace_add;
     binaryfunc nb_inplace_subtract;
     binaryfunc nb_inplace_multiply;
     binaryfunc nb_inplace_remainder;
     ternaryfunc nb_inplace_power;
     binaryfunc nb_inplace_lshift;
     binaryfunc nb_inplace_rshift;
     binaryfunc nb_inplace_and;
     binaryfunc nb_inplace_xor;
     binaryfunc nb_inplace_or;

     binaryfunc nb_floor_divide;
     binaryfunc nb_true_divide;
     binaryfunc nb_inplace_floor_divide;
     binaryfunc nb_inplace_true_divide;

     unaryfunc nb_index;

     binaryfunc nb_matrix_multiply;
     binaryfunc nb_inplace_matrix_multiply;
} PyNumberMethods;

注意

二進位制和三元函式必須檢查其所有運算元的型別,並實現必要的轉換(至少有一個運算元是已定義型別的例項)。如果操作未針對給定的運算元定義,則二進位制和三元函式必須返回 Py_NotImplemented,如果發生其他錯誤,則必須返回 NULL 並設定異常。

注意

nb_reserved 欄位應始終為 NULL。它以前被稱為 nb_long,並在 Python 3.0.1 中重新命名。

binaryfunc PyNumberMethods.nb_add
binaryfunc PyNumberMethods.nb_subtract
binaryfunc PyNumberMethods.nb_multiply
binaryfunc PyNumberMethods.nb_remainder
binaryfunc PyNumberMethods.nb_divmod
ternaryfunc PyNumberMethods.nb_power
unaryfunc PyNumberMethods.nb_negative
unaryfunc PyNumberMethods.nb_positive
unaryfunc PyNumberMethods.nb_absolute
inquiry PyNumberMethods.nb_bool
unaryfunc PyNumberMethods.nb_invert
binaryfunc PyNumberMethods.nb_lshift
binaryfunc PyNumberMethods.nb_rshift
binaryfunc PyNumberMethods.nb_and
binaryfunc PyNumberMethods.nb_xor
binaryfunc PyNumberMethods.nb_or
unaryfunc PyNumberMethods.nb_int
void *PyNumberMethods.nb_reserved
unaryfunc PyNumberMethods.nb_float
binaryfunc PyNumberMethods.nb_inplace_add
binaryfunc PyNumberMethods.nb_inplace_subtract
binaryfunc PyNumberMethods.nb_inplace_multiply
binaryfunc PyNumberMethods.nb_inplace_remainder
ternaryfunc PyNumberMethods.nb_inplace_power
binaryfunc PyNumberMethods.nb_inplace_lshift
binaryfunc PyNumberMethods.nb_inplace_rshift
binaryfunc PyNumberMethods.nb_inplace_and
binaryfunc PyNumberMethods.nb_inplace_xor
binaryfunc PyNumberMethods.nb_inplace_or
binaryfunc PyNumberMethods.nb_floor_divide
binaryfunc PyNumberMethods.nb_true_divide
binaryfunc PyNumberMethods.nb_inplace_floor_divide
binaryfunc PyNumberMethods.nb_inplace_true_divide
unaryfunc PyNumberMethods.nb_index
binaryfunc PyNumberMethods.nb_matrix_multiply
binaryfunc PyNumberMethods.nb_inplace_matrix_multiply

對映物件結構

type PyMappingMethods

此結構體儲存著物件用於實現對映協議的函式的指標。它有三個成員。

lenfunc PyMappingMethods.mp_length

此函式被 PyMapping_Size()PyObject_Size() 使用,並且具有相同的簽名。 如果物件沒有定義的長度,則此槽可以設定為 NULL

binaryfunc PyMappingMethods.mp_subscript

此函式被 PyObject_GetItem()PySequence_GetSlice() 使用,並具有與 PyObject_GetItem() 相同的簽名。為了使 PyMapping_Check() 函式返回 1,必須填寫此槽,否則可以為 NULL

objobjargproc PyMappingMethods.mp_ass_subscript

此函式被 PyObject_SetItem()PyObject_DelItem()PySequence_SetSlice()PySequence_DelSlice() 使用。它具有與 PyObject_SetItem() 相同的簽名,但是 *v* 也可以設定為 NULL 來刪除一個項。如果此槽為 NULL,則該物件不支援項的賦值和刪除。

序列物件結構

type PySequenceMethods

此結構體儲存著物件用於實現序列協議的函式的指標。

lenfunc PySequenceMethods.sq_length

此函式被 PySequence_Size()PyObject_Size() 使用,並且具有相同的簽名。它還用於透過 sq_itemsq_ass_item 插槽處理負索引。

binaryfunc PySequenceMethods.sq_concat

此函式被 PySequence_Concat() 使用,並且具有相同的簽名。它也被 + 運算子使用,在嘗試透過 nb_add 插槽進行數值加法之後。

ssizeargfunc PySequenceMethods.sq_repeat

此函式被 PySequence_Repeat() 使用,並且具有相同的簽名。它也被 * 運算子使用,在嘗試透過 nb_multiply 插槽進行數值乘法之後。

ssizeargfunc PySequenceMethods.sq_item

此函式被 PySequence_GetItem() 使用,並且具有相同的簽名。它也被 PyObject_GetItem() 使用,在嘗試透過 mp_subscript 插槽進行下標操作之後。必須填寫此插槽才能使 PySequence_Check() 函式返回 1,否則它可以為 NULL

負索引的處理方式如下:如果填寫了 sq_length 插槽,則會呼叫該插槽,並使用序列長度計算傳遞給 sq_item 的正索引。如果 sq_lengthNULL,則索引將按原樣傳遞給函式。

ssizeobjargproc PySequenceMethods.sq_ass_item

此函式被 PySequence_SetItem() 使用,並且具有相同的簽名。它也被 PyObject_SetItem()PyObject_DelItem() 使用,在嘗試透過 mp_ass_subscript 插槽進行項賦值和刪除之後。如果物件不支援項賦值和刪除,則可以將此插槽保留為 NULL

objobjproc PySequenceMethods.sq_contains

此函式可以被 PySequence_Contains() 使用,並且具有相同的簽名。可以將此插槽保留為 NULL,在這種情況下,PySequence_Contains() 只會遍歷序列,直到找到匹配項。

binaryfunc PySequenceMethods.sq_inplace_concat

此函式被 PySequence_InPlaceConcat() 使用,並且具有相同的簽名。它應該修改其第一個運算元,並返回它。可以將此插槽保留為 NULL,在這種情況下,PySequence_InPlaceConcat() 將回退到 PySequence_Concat()。它也被增強賦值 += 使用,在嘗試透過 nb_inplace_add 插槽進行數值就地加法之後。

ssizeargfunc PySequenceMethods.sq_inplace_repeat

此函式被 PySequence_InPlaceRepeat() 使用,並且具有相同的簽名。它應該修改其第一個運算元,並返回它。可以將此插槽保留為 NULL,在這種情況下,PySequence_InPlaceRepeat() 將回退到 PySequence_Repeat()。它也被增強賦值 *= 使用,在嘗試透過 nb_inplace_multiply 插槽進行數值就地乘法之後。

緩衝區物件結構

type PyBufferProcs

此結構包含 緩衝區協議 所需的函式的指標。該協議定義了匯出器物件如何向使用者物件公開其內部資料。

getbufferproc PyBufferProcs.bf_getbuffer

此函式的簽名是

int (PyObject *exporter, Py_buffer *view, int flags);

處理 exporter 的請求,以按照 flags 的規定填充 view。除了第 (3) 點之外,此函式的實現必須執行以下步驟

  1. 檢查是否可以滿足請求。如果不能,則引發 BufferError,將 view->obj 設定為 NULL 並返回 -1

  2. 填寫請求的欄位。

  3. 遞增內部計數器,用於記錄匯出的數量。

  4. view->obj 設定為 exporter 並遞增 view->obj

  5. 返回 0

如果 exporter 是緩衝區提供程式鏈或樹的一部分,則可以使用兩種主要方案

  • 重新匯出:樹的每個成員都充當匯出物件,並將 view->obj 設定為對自身的新引用。

  • 重定向:緩衝區請求被重定向到樹的根物件。在這裡,view->obj 將是對根物件的新引用。

view 的各個欄位在 緩衝區結構 部分中描述,匯出器必須如何響應特定請求的規則在 緩衝區請求型別 部分中。

Py_buffer 結構中指向的所有記憶體都屬於匯出者,並且必須保持有效,直到沒有消費者為止。formatshapestridessuboffsetsinternal 對於消費者來說是隻讀的。

PyBuffer_FillInfo() 提供了一種簡單的方法來暴露一個簡單的位元組緩衝區,同時正確處理所有請求型別。

PyObject_GetBuffer() 是消費者的介面,它包裝了這個函式。

releasebufferproc PyBufferProcs.bf_releasebuffer

此函式的簽名是

void (PyObject *exporter, Py_buffer *view);

處理釋放緩衝區資源的請求。如果不需要釋放任何資源,PyBufferProcs.bf_releasebuffer 可以為 NULL。否則,此函式的標準實現將執行這些可選步驟

  1. 遞減匯出次數的內部計數器。

  2. 如果計數器為 0,則釋放與 view 關聯的所有記憶體。

匯出者必須使用 internal 欄位來跟蹤特定於緩衝區的資源。此欄位保證保持不變,而使用者可以傳遞原始緩衝區的副本作為 view 引數。

此函式不得遞減 view->obj,因為這會在 PyBuffer_Release() 中自動完成(此方案對於打破引用迴圈很有用)。

PyBuffer_Release() 是消費者的介面,它包裝了這個函式。

非同步物件結構

在 3.5 版本中新增。

type PyAsyncMethods

此結構儲存實現 可等待物件非同步迭代器 物件所需的函式的指標。

以下是結構體定義

typedef struct {
    unaryfunc am_await;
    unaryfunc am_aiter;
    unaryfunc am_anext;
    sendfunc am_send;
} PyAsyncMethods;
unaryfunc PyAsyncMethods.am_await

此函式的簽名是

PyObject *am_await(PyObject *self);

返回的物件必須是 迭代器,即 PyIter_Check() 必須為其返回 1

如果物件不是 可等待物件,則此槽可以設定為 NULL

unaryfunc PyAsyncMethods.am_aiter

此函式的簽名是

PyObject *am_aiter(PyObject *self);

必須返回一個 非同步迭代器 物件。有關詳細資訊,請參閱 __anext__()

如果物件未實現非同步迭代協議,則此槽可以設定為 NULL

unaryfunc PyAsyncMethods.am_anext

此函式的簽名是

PyObject *am_anext(PyObject *self);

必須返回一個 可等待物件 物件。有關詳細資訊,請參閱 __anext__()。此槽可以設定為 NULL

sendfunc PyAsyncMethods.am_send

此函式的簽名是

PySendResult am_send(PyObject *self, PyObject *arg, PyObject **result);

有關詳細資訊,請參閱 PyIter_Send()。此槽可以設定為 NULL

3.10 版本新增。

槽型別 typedef

typedef PyObject *(*allocfunc)(PyTypeObject *cls, Py_ssize_t nitems)
屬於 穩定 ABI 的一部分。

此函式的目的是將記憶體分配與記憶體初始化分開。它應返回指向例項的足夠長度的記憶體塊的指標,該記憶體塊已適當對齊並初始化為零,但 ob_refcnt 設定為 1,並且 ob_type 設定為型別引數。如果型別的 tp_itemsize 非零,則物件的 ob_size 欄位應初始化為 nitems,並且分配的記憶體塊的長度應為 tp_basicsize + nitems*tp_itemsize,向上舍入為 sizeof(void*) 的倍數;否則,不使用 nitems,塊的長度應為 tp_basicsize

此函式不應執行任何其他例項初始化,甚至不應分配額外的記憶體;這應由 tp_new 完成。

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

請參閱 tp_free

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

請參閱 tp_new

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

請參閱tp_init

typedef PyObject *(*reprfunc)(PyObject*)
屬於 穩定 ABI 的一部分。

請參閱tp_repr

typedef PyObject *(*getattrfunc)(PyObject *self, char *attr)
屬於 穩定 ABI 的一部分。

返回物件的指定屬性的值。

typedef int (*setattrfunc)(PyObject *self, char *attr, PyObject *value)
屬於 穩定 ABI 的一部分。

設定物件的指定屬性的值。如果 value 引數設定為 NULL,則刪除該屬性。

typedef PyObject *(*getattrofunc)(PyObject *self, PyObject *attr)
屬於 穩定 ABI 的一部分。

返回物件的指定屬性的值。

請參閱tp_getattro

typedef int (*setattrofunc)(PyObject *self, PyObject *attr, PyObject *value)
屬於 穩定 ABI 的一部分。

設定物件的指定屬性的值。如果 value 引數設定為 NULL,則刪除該屬性。

請參閱tp_setattro

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

請參閱tp_descr_get

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

請參閱tp_descr_set

typedef Py_hash_t (*hashfunc)(PyObject*)
屬於 穩定 ABI 的一部分。

請參閱tp_hash

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

請參閱tp_richcompare

typedef PyObject *(*getiterfunc)(PyObject*)
屬於 穩定 ABI 的一部分。

請參閱tp_iter

typedef PyObject *(*iternextfunc)(PyObject*)
屬於 穩定 ABI 的一部分。

請參閱tp_iternext

typedef Py_ssize_t (*lenfunc)(PyObject*)
屬於 穩定 ABI 的一部分。
typedef int (*getbufferproc)(PyObject*, Py_buffer*, int)
自 3.12 版本起,屬於 穩定 ABI 的一部分。
typedef void (*releasebufferproc)(PyObject*, Py_buffer*)
自 3.12 版本起,屬於 穩定 ABI 的一部分。
typedef PyObject *(*unaryfunc)(PyObject*)
屬於 穩定 ABI 的一部分。
typedef PyObject *(*binaryfunc)(PyObject*, PyObject*)
屬於 穩定 ABI 的一部分。
typedef PySendResult (*sendfunc)(PyObject*, PyObject*, PyObject**)

請參考 am_send

typedef PyObject *(*ternaryfunc)(PyObject*, PyObject*, PyObject*)
屬於 穩定 ABI 的一部分。
typedef PyObject *(*ssizeargfunc)(PyObject*, Py_ssize_t)
屬於 穩定 ABI 的一部分。
typedef int (*ssizeobjargproc)(PyObject*, Py_ssize_t, PyObject*)
屬於 穩定 ABI 的一部分。
typedef int (*objobjproc)(PyObject*, PyObject*)
屬於 穩定 ABI 的一部分。
typedef int (*objobjargproc)(PyObject*, PyObject*, PyObject*)
屬於 穩定 ABI 的一部分。

示例

以下是一些 Python 型別定義的基本示例。它們包括您可能遇到的常見用法。有些演示了棘手的邊緣情況。有關更多示例、實用資訊和教程,請參閱 定義擴充套件型別:教程定義擴充套件型別:各種主題

一個基本的 靜態型別

typedef struct {
    PyObject_HEAD
    const char *data;
} MyObject;

static PyTypeObject MyObject_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "mymod.MyObject",
    .tp_basicsize = sizeof(MyObject),
    .tp_doc = PyDoc_STR("My objects"),
    .tp_new = myobj_new,
    .tp_dealloc = (destructor)myobj_dealloc,
    .tp_repr = (reprfunc)myobj_repr,
};

您還可能會發現較舊的程式碼(尤其是在 CPython 程式碼庫中)使用了更詳細的初始化程式

static PyTypeObject MyObject_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "mymod.MyObject",               /* tp_name */
    sizeof(MyObject),               /* tp_basicsize */
    0,                              /* tp_itemsize */
    (destructor)myobj_dealloc,      /* tp_dealloc */
    0,                              /* tp_vectorcall_offset */
    0,                              /* tp_getattr */
    0,                              /* tp_setattr */
    0,                              /* tp_as_async */
    (reprfunc)myobj_repr,           /* tp_repr */
    0,                              /* tp_as_number */
    0,                              /* tp_as_sequence */
    0,                              /* tp_as_mapping */
    0,                              /* tp_hash */
    0,                              /* tp_call */
    0,                              /* tp_str */
    0,                              /* tp_getattro */
    0,                              /* tp_setattro */
    0,                              /* tp_as_buffer */
    0,                              /* tp_flags */
    PyDoc_STR("My objects"),        /* tp_doc */
    0,                              /* tp_traverse */
    0,                              /* tp_clear */
    0,                              /* tp_richcompare */
    0,                              /* tp_weaklistoffset */
    0,                              /* tp_iter */
    0,                              /* tp_iternext */
    0,                              /* tp_methods */
    0,                              /* tp_members */
    0,                              /* tp_getset */
    0,                              /* tp_base */
    0,                              /* tp_dict */
    0,                              /* tp_descr_get */
    0,                              /* tp_descr_set */
    0,                              /* tp_dictoffset */
    0,                              /* tp_init */
    0,                              /* tp_alloc */
    myobj_new,                      /* tp_new */
};

一個支援弱引用、例項字典和雜湊的型別

typedef struct {
    PyObject_HEAD
    const char *data;
} MyObject;

static PyTypeObject MyObject_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "mymod.MyObject",
    .tp_basicsize = sizeof(MyObject),
    .tp_doc = PyDoc_STR("My objects"),
    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
         Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_MANAGED_DICT |
         Py_TPFLAGS_MANAGED_WEAKREF,
    .tp_new = myobj_new,
    .tp_traverse = (traverseproc)myobj_traverse,
    .tp_clear = (inquiry)myobj_clear,
    .tp_alloc = PyType_GenericNew,
    .tp_dealloc = (destructor)myobj_dealloc,
    .tp_repr = (reprfunc)myobj_repr,
    .tp_hash = (hashfunc)myobj_hash,
    .tp_richcompare = PyBaseObject_Type.tp_richcompare,
};

一個不能被子類化並且不能被呼叫來建立例項(例如,使用單獨的工廠函式)的 str 子類,使用 Py_TPFLAGS_DISALLOW_INSTANTIATION 標誌

typedef struct {
    PyUnicodeObject raw;
    char *extra;
} MyStr;

static PyTypeObject MyStr_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "mymod.MyStr",
    .tp_basicsize = sizeof(MyStr),
    .tp_base = NULL,  // set to &PyUnicode_Type in module init
    .tp_doc = PyDoc_STR("my custom str"),
    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
    .tp_repr = (reprfunc)myobj_repr,
};

最簡單的具有固定長度例項的靜態型別

typedef struct {
    PyObject_HEAD
} MyObject;

static PyTypeObject MyObject_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "mymod.MyObject",
};

最簡單的具有可變長度例項的靜態型別

typedef struct {
    PyObject_VAR_HEAD
    const char *data[1];
} MyObject;

static PyTypeObject MyObject_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "mymod.MyObject",
    .tp_basicsize = sizeof(MyObject) - sizeof(char *),
    .tp_itemsize = sizeof(char *),
};