型別物件結構

也許 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()

__buffer__

bf_releasebuffer

releasebufferproc()

__release_buffer__

槽位 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/cpython/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 */
    PyMethodDef *tp_methods;
    PyMemberDef *tp_members;
    PyGetSetDef *tp_getset;
    // Strong reference on a heap type, borrowed reference on a static type
    PyTypeObject *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; /* no longer used */
    void *tp_subclasses;  /* for static builtin types this is an index */
    PyObject *tp_weaklist; /* not used for static builtin types */
    destructor tp_del;

    /* Type attribute cache version tag. Added in version 2.6.
     * If zero, the cache is invalid and must be initialized.
     */
    unsigned int tp_version_tag;

    destructor tp_finalize;
    vectorcallfunc tp_vectorcall;

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

    /* Number of tp_version_tag values used.
     * Set to _Py_ATTR_CACHE_UNUSED if the attribute cache is
     * disabled for this type (e.g. due to custom MRO entries).
     * Otherwise, limited to MAX_VERSIONS_PER_CLASS (defined elsewhere).
     */
    uint16_t tp_versions_used;
} PyTypeObject;

PyObject 槽位

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

PyObject.ob_refcnt

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

繼承

此欄位不被子型別繼承。

PyObject.ob_type

這是型別的型別,換句話說就是它的元型別。它由 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 槽位

PyVarObject.ob_size

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

此欄位應使用 Py_SIZE() 宏訪問。

繼承

此欄位不被子型別繼承。

PyTypeObject 槽位

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

const char *PyTypeObject.tp_name

指向一個以 NUL 結尾的字串的指標,該字串包含型別的名稱。對於可作為模組全域性變數訪問的型別,字串應為完整的模組名稱,後跟一個點,再後跟型別名稱;對於內建型別,它應僅為型別名稱。如果模組是包的子模組,則完整的包名稱是完整模組名稱的一部分。例如,在包 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 中給出。(可以使用 PyUnstable_Object_GC_NewWithExtraData() 對此規則進行例外處理。)

對於可變長度例項的型別,例項必須具有 ob_size 欄位,並且例項大小為 tp_basicsize 加上 N 乘以 tp_itemsize,其中 N 是物件的“長度”。

PyObject_NewVar() 這樣的函式將以 N 的值作為引數,並將其儲存在例項的 ob_size 欄位中。請注意,ob_size 欄位以後可能用於其他目的。例如,int 例項以實現定義的方式使用 ob_size 的位;應使用 PyLong_Export() 訪問底層儲存及其大小。

備註

ob_size 欄位應使用 Py_SIZE()Py_SET_SIZE() 宏訪問。

此外,例項佈局中存在 ob_size 欄位並不意味著例項結構是可變長度的。例如,list 型別具有固定長度的例項,但這些例項具有 ob_size 欄位。(與 int 一樣,避免直接讀取列表的 ob_size。而是呼叫 PyList_Size()。)

tp_basicsize 包括型別 tp_base 的資料所需的大小,以及每個例項所需的任何額外資料。

設定 tp_basicsize 的正確方法是對用於宣告例項佈局的結構使用 sizeof 運算子。此結構必須包含用於宣告基型別的結構。換句話說,tp_basicsize 必須大於或等於基類的 tp_basicsize

由於每個型別都是 object 的子型別,因此此結構必須包含 PyObjectPyVarObject(取決於是否應包含 ob_size)。這些通常分別由宏 PyObject_HEADPyObject_VAR_HEAD 定義。

基本大小不包括 GC 頭大小,因為該頭不是 PyObject_HEAD 的一部分。

對於用於宣告基型別的結構未知的情況,請參閱 PyType_Spec.basicsizePyType_FromMetaclass()

關於對齊的注意事項

  • tp_basicsize 必須是 _Alignof(PyObject) 的倍數。當對包含 PyObject_HEADstruct 使用 sizeof 時(如推薦的那樣),編譯器會確保這一點。不使用 C struct 時,或使用像 __attribute__((packed)) 這樣的編譯器擴充套件時,由您負責。

  • 如果可變項需要特定的對齊方式,則 tp_basicsizetp_itemsize 都必須是該對齊方式的倍數。例如,如果型別的可變部分儲存 double,則您有責任確保這兩個欄位都是 _Alignof(double) 的倍數。

繼承

這些欄位由子型別單獨繼承。(也就是說,如果欄位設定為零,PyType_Ready() 將從基型別複製該值,表示例項不需要額外的儲存。)

如果基型別具有非零 tp_itemsize,則通常不安全在子型別中將 tp_itemsize 設定為不同的非零值(儘管這取決於基型別的實現)。

destructor PyTypeObject.tp_dealloc

指向例項解構函式的指標。函式簽名是

void tp_dealloc(PyObject *self);

解構函式應移除例項擁有的所有引用(例如,呼叫 Py_CLEAR()),釋放例項擁有的所有記憶體緩衝區,並呼叫型別的 tp_free 函式以釋放物件本身。

如果您可能呼叫可能設定錯誤指示器的函式,則必須使用 PyErr_GetRaisedException()PyErr_SetRaisedException() 以確保您不會覆蓋預先存在的錯誤指示器(在處理不同的錯誤時可能發生瞭解除分配)

static void
foo_dealloc(foo_object *self)
{
    PyObject *et, *ev, *etb;
    PyObject *exc = PyErr_GetRaisedException();
    ...
    PyErr_SetRaisedException(exc);
}

dealloc 處理程式本身不得引發異常;如果遇到錯誤情況,它應該呼叫 PyErr_FormatUnraisable() 來記錄(並清除)一個不可引發的異常。

不保證何時銷燬物件,除了

  • Python 將在刪除物件的最終引用後立即或一段時間後銷燬物件,除非其終結器(tp_finalize)隨後復活了物件。

  • 物件在自動終結(tp_finalize)或自動清除(tp_clear)時不會被銷燬。

CPython 目前在 Py_DECREF() 中,當新的引用計數為零時立即銷燬物件,但這可能會在將來的版本中改變。

建議在 tp_dealloc 的開頭呼叫 PyObject_CallFinalizerFromDealloc(),以保證物件在銷燬前始終被終結。

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

允許從 tp_dealloc 呼叫 tp_clear 以減少程式碼重複並保證物件在銷燬前始終被清除。請注意,tp_clear 可能已經被呼叫。

如果型別是堆分配的(Py_TPFLAGS_HEAPTYPE),解構函式應在呼叫型別解構函式後釋放其對型別物件擁有的引用(透過 Py_DECREF())。請參閱下面的示例程式碼。

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

tp_dealloc 必須保持異常狀態不變。如果它需要呼叫可能引發異常的東西,則必須首先備份異常狀態,然後在以後恢復(在用 PyErr_WriteUnraisable() 記錄任何異常之後)。

示例

static void
foo_dealloc(PyObject *self)
{
    PyObject *exc = PyErr_GetRaisedException();

    if (PyObject_CallFinalizerFromDealloc(self) < 0) {
        // self was resurrected.
        goto done;
    }

    PyTypeObject *tp = Py_TYPE(self);

    if (tp->tp_flags & Py_TPFLAGS_HAVE_GC) {
        PyObject_GC_UnTrack(self);
    }

    // Optional, but convenient to avoid code duplication.
    if (tp->tp_clear && tp->tp_clear(self) < 0) {
        PyErr_WriteUnraisable(self);
    }

    // Any additional destruction goes here.

    tp->tp_free(self);
    self = NULL;  // In case PyErr_WriteUnraisable() is called below.

    if (tp->tp_flags & Py_TPFLAGS_HEAPTYPE) {
        Py_CLEAR(tp);
    }

done:
    // Optional, if something was called that might have raised an
    // exception.
    if (PyErr_Occurred()) {
        PyErr_WriteUnraisable(self);
    }
    PyErr_SetRaisedException(exc);
}

tp_dealloc 可以在任何 Python 執行緒中呼叫,而不僅僅是建立物件的執行緒(如果物件成為引用計數迴圈的一部分,該迴圈可能會被任何執行緒上的垃圾回收收集)。這對於 Python API 呼叫來說不是問題,因為呼叫 tp_dealloc 的執行緒具有附加的執行緒狀態。但是,如果被銷燬的物件反過來銷燬來自其他 C 庫的物件,則應注意確保在呼叫 tp_dealloc 的執行緒上銷燬這些物件不會違反庫的任何假設。

繼承

此欄位被子型別繼承。

參見

有關此槽位與其他槽位如何關聯的詳細資訊,請參閱物件生命週期

Py_ssize_t PyTypeObject.tp_vectorcall_offset

一個可選的偏移量,指向一個實現使用向量呼叫協議呼叫物件的例項函式,它是更簡單的 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 版之前,不建議可變堆型別實現向量呼叫協議。當用戶在 Python 程式碼中設定 __call__ 時,只有 *tp_call* 會更新,這很可能使其與向量呼叫函式不一致。自 3.12 版起,設定 __call__ 將透過清除 Py_TPFLAGS_HAVE_VECTORCALL 標誌來停用向量呼叫最佳化。

繼承

此欄位始終繼承。但是,Py_TPFLAGS_HAVE_VECTORCALL 標誌並非始終繼承。如果未設定,則子類將不使用向量呼叫,除非明確呼叫了 PyVectorcall_Call()

getattrfunc PyTypeObject.tp_getattr

指向 get-attribute-string 函式的可選指標。

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

繼承

組:tp_getattrtp_getattro

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

setattrfunc PyTypeObject.tp_setattr

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

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

繼承

組:tp_setattrtp_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 設定為 PyObject_HashNotImplemented() 將導致 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

指向 get-attribute 函式的可選指標。

簽名與 PyObject_GetAttr() 相同

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

通常方便將此欄位設定為 PyObject_GenericGetAttr(),它實現了查詢物件屬性的正常方式。

繼承

組:tp_getattrtp_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_setattrtp_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

預設

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

當物件支援垃圾回收時,此位被設定。如果此位被設定,則新例項的記憶體(參見 tp_alloc)必須使用 PyObject_GC_NewPyType_GenericAlloc() 分配,並使用 PyObject_GC_Del() 釋放(參見 tp_free)。更多資訊請參見 支援迴圈垃圾回收 一節。

繼承

組: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

此位表示類的例項具有 __dict__ 屬性,並且字典的空間由 VM 管理。

如果設定了此標誌,則也應設定 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

當類實現 向量呼叫協議 時,此位被設定。詳見 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_Typetp_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(PyObject *op, visitproc visit, void *arg)
{
    localobject *self = (localobject *) op;
    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 位,則遍歷函式必須像這樣呼叫 PyObject_VisitManagedDict()

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

警告

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

請注意,Py_VISIT() 要求 local_traverse()visitarg 引數具有這些特定名稱;不要隨便命名它們。

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

備註

tp_traverse 函式可以在任何執行緒中呼叫。

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

繼承

組:Py_TPFLAGS_HAVE_GCtp_traversetp_clear

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

inquiry PyTypeObject.tp_clear

指向清除函式的可選指標。其簽名為

int tp_clear(PyObject *);

此函式的目的是打破導致 迴圈隔離 的引用迴圈,以便安全地銷燬物件。清除的物件是部分銷燬的物件;物件沒有義務滿足正常使用期間所保持的設計不變數。

tp_clear 不需要刪除對不能參與引用迴圈的物件的引用,例如 Python 字串或 Python 整數。但是,清除所有引用可能很方便,並且編寫型別的 tp_dealloc 函式以呼叫 tp_clear 以避免程式碼重複。(請注意,tp_clear 可能已經呼叫過。優先呼叫冪等函式,如 Py_CLEAR()。)

任何非平凡的清理都應在 tp_finalize 中執行,而不是在 tp_clear 中執行。

備註

如果 tp_clear 未能打破引用迴圈,則 迴圈隔離 中的物件可能無限期地無法回收(“洩漏”)。參見 gc.garbage

備註

被引用者(直接和間接)可能已經被清除;它們不保證處於一致狀態。

備註

tp_clear 函式可以在任何執行緒中呼叫。

備註

不能保證物件在其解構函式(tp_dealloc)被呼叫之前自動清除。

此函式與解構函式(tp_dealloc)在以下方面有所不同

  • 清除物件的目的是移除對可能參與引用迴圈的其他物件的引用。另一方面,解構函式的目的是一個超集:它必須釋放其擁有的 所有 資源,包括對不能參與引用迴圈的物件的引用(例如,整數)以及物件自身的記憶體(透過呼叫 tp_free)。

  • 當呼叫 tp_clear 時,其他物件可能仍然持有對正在清除的物件的引用。因此,tp_clear 不得釋放物件自身的記憶體(tp_free)。另一方面,解構函式僅在沒有(強)引用存在時才呼叫,因此必須透過釋放物件來安全地銷燬物件本身。

  • tp_clear 可能永遠不會被自動呼叫。另一方面,物件的解構函式將在物件變為不可達後(即,不存在對該物件的引用,或者該物件是 迴圈隔離 的成員)的某個時間點自動呼叫。

Python 不保證何時、是否或多久自動清除一個物件,但以下情況除外:

  • 如果一個物件是可達的,即存在對它的引用且它不是 迴圈隔離 的成員,Python 將不會自動清除它。

  • 如果一個物件尚未被自動終結(參見 tp_finalize),Python 將不會自動清除它。(如果終結器使物件復活,則在清除之前,該物件可能會或可能不會再次自動終結。)

  • 如果一個物件是 迴圈隔離 的成員,如果迴圈隔離的任何成員尚未被自動終結(tp_finalize),Python 將不會自動清除它。

  • Python 不會在其 tp_clear 函式的任何自動呼叫返回之前銷燬物件。這確保了在 tp_clear 仍在執行時,打破引用迴圈的行為不會使 self 指標無效。

  • Python 不會自動併發呼叫 tp_clear 多次。

CPython 目前只根據需要自動清除物件,以打破 迴圈隔離 中的引用迴圈,但未來的版本可能會在物件銷燬之前定期清除物件。

總而言之,系統中所有 tp_clear 函式必須結合起來打破所有引用迴圈。這很微妙,如有任何疑問,請提供一個 tp_clear 函式。例如,元組型別沒有實現 tp_clear 函式,因為可以證明沒有引用迴圈完全由元組組成。因此,其他型別的 tp_clear 函式負責打破任何包含元組的迴圈。這並不立即顯而易見,並且很少有充分的理由避免實現 tp_clear

tp_clear 的實現應放棄例項對其 Python 物件成員的引用,並將其指向這些成員的指標設定為 NULL,示例如下:

static int
local_clear(PyObject *op)
{
    localobject *self = (localobject *) op;
    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);

有關 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 不支援。這兩種編譯器在此特定行為上都嚴格符合標準。

因此,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() 獲取任意型別的字典。

繼承

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

預設

如果此欄位為 NULLPyType_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_DICT 位和 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);

繼承

靜態子型別繼承此槽,如果從 object 繼承,它將是 PyType_GenericAlloc()

堆子型別不繼承此槽。

預設

對於堆子型別,此欄位始終設定為 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);

此函式必須釋放由 tp_alloc 分配的記憶體。

繼承

靜態子型別繼承此槽,如果從 object 繼承,它將是 PyObject_Free()。例外:如果型別支援垃圾回收(即,Py_TPFLAGS_HAVE_GC 標誌在 tp_flags 中設定)並且它將繼承 PyObject_Free(),則此槽不繼承,而是預設為 PyObject_GC_Del()

堆子型別不繼承此槽。

預設

對於 堆子型別,此槽預設為與 PyType_GenericAlloc()Py_TPFLAGS_HAVE_GC 標誌的值匹配的解除分配器。

對於靜態子型別,此槽是繼承的(見上文)。

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 slot 代替 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

指向例項終結函式的可選指標。這是 __del__() 特殊方法的 C 實現。其簽名是

void tp_finalize(PyObject *self);

終結的主要目的是在物件被銷燬之前,當物件及其直接或間接引用的任何其他物件仍處於一致狀態時,執行任何必須執行的非平凡清理。終結器可以執行任意 Python 程式碼。

在 Python 自動終結物件之前,物件的某些直接或間接引用者可能已自行自動終結。但是,尚未自動清除任何引用者 (tp_clear)。

其他未終結的物件可能仍在使用已終結的物件,因此終結器必須使物件處於健全狀態(例如,不變數仍然滿足)。

備註

在 Python 自動終結物件之後,Python 可能會開始自動清除 (tp_clear) 物件及其引用者(直接和間接)。清除的物件不保證處於一致狀態;已終結的物件必須能夠容忍已清除的引用者。

備註

不保證物件在呼叫其解構函式 (tp_dealloc) 之前被自動終結。建議在 tp_dealloc 開始時呼叫 PyObject_CallFinalizerFromDealloc(),以保證物件在銷燬之前始終被終結。

備註

tp_finalize 函式可以從任何執行緒呼叫,儘管 GIL 將被持有。

備註

tp_finalize 函式可以在關機期間呼叫,在某些全域性變數被刪除之後。有關詳細資訊,請參閱 __del__() 方法的文件。

當 Python 終結一個物件時,它會按以下演算法執行

  1. Python 可能會將物件標記為 finalized。目前,Python 總是標記其型別支援垃圾回收(即 Py_TPFLAGS_HAVE_GC 標誌在 tp_flags 中設定)的物件,並且從不標記其他型別的物件;這可能會在未來版本中改變。

  2. 如果物件未標記為 finalized 且其 tp_finalize 終結器函式不為 NULL,則呼叫終結器函式。

  3. 如果終結器函式被呼叫,並且終結器使物件可達(即,存在對物件的引用,並且它不是迴圈隔離的成員),則稱終結器已 resurrected 物件。關於終結器是否還可以透過向物件新增一個新的不使其可達的引用來複活物件,即物件(仍然)是迴圈隔離的成員,這是未指明的。

  4. 如果終結器復活了物件,則物件的待定銷燬被取消,並且如果存在,物件的 finalized 標記可能會被刪除。目前,Python 從不刪除 finalized 標記;這可能會在未來版本中改變。

自動終結 是指 Python 執行的任何終結,但透過呼叫 PyObject_CallFinalizer()PyObject_CallFinalizerFromDealloc() 除外。關於物件何時、是否或多久自動終結,不作任何保證,除了

  • 如果物件可達(即,存在對它的引用,並且它不是迴圈隔離的成員),Python 將不會自動終結該物件。

  • 如果終結物件不會將物件標記為 finalized,Python 將不會自動終結該物件。目前,這適用於其型別不支援垃圾回收的物件,即 Py_TPFLAGS_HAVE_GC 標誌未設定的物件。此類物件仍然可以透過呼叫 PyObject_CallFinalizer()PyObject_CallFinalizerFromDealloc() 來手動終結。

  • Python 不會同時自動終結迴圈隔離的任何兩個成員。

  • Python 在自動清除 (tp_clear) 物件後,將不會自動終結該物件。

  • 如果物件是迴圈隔離的成員,Python 在自動清除(參見 tp_clear)任何其他成員後,將不會自動終結它。

  • Python 將自動終結迴圈隔離的每個成員,然後才自動清除(參見 tp_clear)其中任何一個。

  • 如果 Python 要自動清除一個物件 (tp_clear),它將首先自動終結該物件。

Python 目前僅自動終結迴圈隔離的成員物件,但未來版本可能會在銷燬前定期終結物件。

要手動終結物件,不要直接呼叫此函式;請改用 PyObject_CallFinalizer()PyObject_CallFinalizerFromDealloc()

tp_finalize 應該保持當前異常狀態不變。編寫非平凡終結器的推薦方法是在開始時透過呼叫 PyErr_GetRaisedException() 備份異常,並在結束時透過呼叫 PyErr_SetRaisedException() 恢復異常。如果在終結器中間遇到異常,請使用 PyErr_WriteUnraisable()PyErr_FormatUnraisable() 記錄並清除它。例如

static void
foo_finalize(PyObject *self)
{
    // Save the current exception, if any.
    PyObject *exc = PyErr_GetRaisedException();

    // ...

    if (do_something_that_might_raise() != success_indicator) {
        PyErr_WriteUnraisable(self);
        goto done;
    }

done:
    // Restore the saved exception.  This silently discards any exception
    // raised above, so be sure to call PyErr_WriteUnraisable first if
    // necessary.
    PyErr_SetRaisedException(exc);
}

繼承

此欄位被子型別繼承。

在 3.4 版本加入。

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

參見

vectorcallfunc PyTypeObject.tp_vectorcall

用於呼叫此型別物件(而不是例項)的 向量呼叫函式。換句話說,tp_vectorcall 可用於最佳化 type.__call__,它通常返回 type 的新例項。

與任何向量呼叫函式一樣,如果 tp_vectorcallNULL,則使用 tp_call 協議(Py_TYPE(type)->tp_call)代替。

備註

向量呼叫協議 要求向量呼叫函式具有與相應 tp_call 相同的行為。這意味著 type->tp_vectorcall 必須與 Py_TYPE(type)->tp_call 的行為匹配。

具體來說,如果 type 使用預設元類,則 type->tp_vectorcall 必須與 PyType_Type->tp_call 的行為相同,它

  • 呼叫 type->tp_new

  • 如果結果是 type 的子類,則在 tp_new 的結果上呼叫 type->tp_init,並且

  • 返回 tp_new 的結果。

通常,會覆蓋 tp_vectorcall 以最佳化特定 tp_newtp_init 的此過程。在為使用者可子類化的型別執行此操作時,請注意兩者都可以被覆蓋(分別使用 __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 PyObject *(*allocfunc)(PyTypeObject *cls, Py_ssize_t nitems)
作為 穩定 ABI 的一部分。

此函式旨在將記憶體分配與記憶體初始化分離。它應該返回一個指向記憶體塊的指標,該記憶體塊具有適合例項的足夠長度,適當對齊,並初始化為零,但 ob_refcnt 設定為 1ob_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)(PyTypeObject*, 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 Py_ssize_t (*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 *),
};