型別物件結構¶
也許 Python 物件系統最重要的結構之一是定義新型別的結構:PyTypeObject
結構。型別物件可以使用任何 PyObject_*
或 PyType_*
函式來處理,但對於大多數 Python 應用程式來說,它們並沒有提供太多有趣的東西。這些物件是物件行為的基礎,因此它們對於直譯器本身以及實現新型別的任何擴充套件模組都非常重要。
型別物件與大多數標準型別相比相當大。尺寸大的原因是每個型別物件儲存了大量的值,大部分是 C 函式指標,每個指標都實現了型別功能的一小部分。本節將詳細檢查型別物件的欄位。欄位將按它們在結構中出現的順序進行描述。
除了以下快速參考,示例部分提供了對 PyTypeObject
的含義和用法的直觀理解。
快速參考¶
“tp 槽位”¶
PyTypeObject 槽位 [1] |
特殊方法/屬性 |
資訊 [2] |
||||
---|---|---|---|---|---|---|
O |
T |
D |
I |
|||
<R> |
const char * |
__name__ |
X |
X |
||
X |
X |
X |
||||
X |
X |
|||||
X |
X |
X |
||||
X |
X |
|||||
__getattribute__, __getattr__ |
G |
|||||
__setattr__, __delattr__ |
G |
|||||
% |
||||||
__repr__ |
X |
X |
X |
|||
% |
||||||
% |
||||||
% |
||||||
__hash__ |
X |
G |
||||
__call__ |
X |
X |
||||
__str__ |
X |
X |
||||
__getattribute__, __getattr__ |
X |
X |
G |
|||
__setattr__, __delattr__ |
X |
X |
G |
|||
% |
||||||
unsigned long |
X |
X |
? |
|||
const char * |
__doc__ |
X |
X |
|||
X |
G |
|||||
X |
G |
|||||
__lt__, __le__, __eq__, __ne__, __gt__, __ge__ |
X |
G |
||||
X |
? |
|||||
__iter__ |
X |
|||||
__next__ |
X |
|||||
|
X |
X |
||||
|
X |
|||||
|
X |
X |
||||
__base__ |
X |
|||||
|
__dict__ |
? |
||||
__get__ |
X |
|||||
__set__, __delete__ |
X |
|||||
X |
? |
|||||
__init__ |
X |
X |
X |
|||
X |
? |
? |
||||
__new__ |
X |
X |
? |
? |
||
X |
X |
? |
? |
|||
X |
X |
|||||
< |
|
__bases__ |
~ |
|||
< |
|
__mro__ |
~ |
|||
[ |
|
|||||
void * |
__subclasses__ |
|||||
|
||||||
( |
||||||
unsigned int |
||||||
__del__ |
X |
|||||
unsigned char |
子槽位¶
槽位 |
特殊方法 |
|
---|---|---|
__await__ |
||
__aiter__ |
||
__anext__ |
||
__add__ __radd__ |
||
__iadd__ |
||
__sub__ __rsub__ |
||
__isub__ |
||
__mul__ __rmul__ |
||
__imul__ |
||
__mod__ __rmod__ |
||
__imod__ |
||
__divmod__ __rdivmod__ |
||
__pow__ __rpow__ |
||
__ipow__ |
||
__neg__ |
||
__pos__ |
||
__abs__ |
||
__bool__ |
||
__invert__ |
||
__lshift__ __rlshift__ |
||
__ilshift__ |
||
__rshift__ __rrshift__ |
||
__irshift__ |
||
__and__ __rand__ |
||
__iand__ |
||
__xor__ __rxor__ |
||
__ixor__ |
||
__or__ __ror__ |
||
__ior__ |
||
__int__ |
||
void * |
||
__float__ |
||
__floordiv__ |
||
__ifloordiv__ |
||
__truediv__ |
||
__itruediv__ |
||
__index__ |
||
__matmul__ __rmatmul__ |
||
__imatmul__ |
||
__len__ |
||
__getitem__ |
||
__setitem__, __delitem__ |
||
__len__ |
||
__add__ |
||
__mul__ |
||
__getitem__ |
||
__setitem__ __delitem__ |
||
__contains__ |
||
__iadd__ |
||
__imul__ |
||
__buffer__ |
||
__release_buffer__ |
槽位 typedef¶
typedef |
引數型別 |
返回型別 |
---|---|---|
|
||
|
void |
|
void * |
void |
|
int |
||
|
||
int |
||
|
|
|
PyObject *const char *
|
|
|
int |
||
|
||
int |
||
|
||
int |
||
|
Py_hash_t |
|
|
||
|
|
|
|
|
|
|
||
int |
||
void |
||
|
int |
|
PyObject * |
|
|
|
||
|
||
|
||
int |
||
int |
||
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_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 槽位¶
PyTypeObject 槽位¶
每個槽位都有一個描述繼承的部分。如果 PyType_Ready()
在欄位設定為 NULL
時可以設定一個值,那麼還將有一個“預設”部分。(請注意,在 PyBaseObject_Type
和 PyType_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
的子型別,因此此結構必須包含PyObject
或PyVarObject
(取決於是否應包含ob_size
)。這些通常分別由宏PyObject_HEAD
或PyObject_VAR_HEAD
定義。基本大小不包括 GC 頭大小,因為該頭不是
PyObject_HEAD
的一部分。對於用於宣告基型別的結構未知的情況,請參閱
PyType_Spec.basicsize
和PyType_FromMetaclass()
。關於對齊的注意事項
tp_basicsize
必須是_Alignof(PyObject)
的倍數。當對包含PyObject_HEAD
的struct
使用sizeof
時(如推薦的那樣),編譯器會確保這一點。不使用 Cstruct
時,或使用像__attribute__((packed))
這樣的編譯器擴充套件時,由您負責。如果可變項需要特定的對齊方式,則
tp_basicsize
和tp_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_getattro
一起被子型別繼承:當子型別的tp_getattr
和tp_getattro
都為NULL
時,子型別會從其基型別繼承tp_getattr
和tp_getattro
。
-
setattrfunc PyTypeObject.tp_setattr¶
指向用於設定和刪除屬性的函式的可選指標。
此欄位已棄用。當它被定義時,它應該指向一個與
tp_setattro
函式行為相同的函式,但使用 C 字串而不是 Python 字串物件來提供屬性名稱。繼承
此欄位與
tp_setattro
一起被子型別繼承:當子型別的tp_setattr
和tp_setattro
都為NULL
時,子型別會從其基型別繼承tp_setattr
和tp_setattro
。
-
PyAsyncMethods *PyTypeObject.tp_as_async¶
指向一個附加結構的指標,該結構包含僅與在 C 級別實現可等待和非同步迭代器協議的物件相關的欄位。有關詳細資訊,請參見非同步物件結構。
3.5 新增: 以前稱為
tp_compare
和tp_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_richcompare
一起被子型別繼承:當子型別的tp_richcompare
和tp_hash
都為NULL
時,子型別會繼承tp_richcompare
和tp_hash
。預設
-
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_getattr
一起被子型別繼承:當子型別的tp_getattr
和tp_getattro
都為NULL
時,子型別會從其基型別繼承tp_getattr
和tp_getattro
。預設
-
setattrofunc PyTypeObject.tp_setattro¶
指向用於設定和刪除屬性的函式的可選指標。
簽名與
PyObject_SetAttr()
相同int tp_setattro(PyObject *self, PyObject *attr, PyObject *value);
此外,還必須支援將 value 設定為
NULL
以刪除屬性。通常方便將此欄位設定為PyObject_GenericSetAttr()
,它實現了設定物件屬性的正常方式。繼承
此欄位由子型別與
tp_setattr
一起繼承:當子型別的tp_setattr
和tp_setattro
都為NULL
時,子型別會從其基型別繼承tp_setattr
和tp_setattro
。預設
-
PyBufferProcs *PyTypeObject.tp_as_buffer¶
指向一個附加結構的指標,該結構包含僅與實現緩衝區介面的物件相關的欄位。這些欄位在 緩衝區物件結構 中有詳細說明。
繼承
tp_as_buffer
欄位不被繼承,但其包含的欄位會單獨繼承。
-
unsigned long PyTypeObject.tp_flags¶
此欄位是各種標誌的位掩碼。有些標誌表示特定情況下的不同語義;其他標誌用於指示型別物件中(或透過
tp_as_number
、tp_as_sequence
、tp_as_mapping
和tp_as_buffer
引用的擴充套件結構中)歷史上不總是存在的某些欄位是有效的;如果此類標誌位不清除,則不能訪問其保護的型別欄位,並且必須將其視為具有零或NULL
值。繼承
此欄位的繼承很複雜。大多數標誌位是單獨繼承的,即如果基型別設定了某個標誌位,則子型別繼承該標誌位。與擴充套件結構相關的標誌位在擴充套件結構被繼承時嚴格繼承,即基型別的標誌位值與指向擴充套件結構的指標一起復制到子型別中。
Py_TPFLAGS_HAVE_GC
標誌位與tp_traverse
和tp_clear
欄位一起繼承,即如果子型別中Py_TPFLAGS_HAVE_GC
標誌位為清除狀態,並且子型別中的tp_traverse
和tp_clear
欄位存在且值為NULL
。預設
PyBaseObject_Type
使用Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
。位掩碼
目前定義了以下位掩碼;可以使用
|
運算子將它們進行或運算,以形成tp_flags
欄位的值。宏PyType_HasFeature()
接受一個型別和標誌值,即 tp 和 f,並檢查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_New
或PyType_GenericAlloc()
分配,並使用PyObject_GC_Del()
釋放(參見tp_free
)。更多資訊請參見 支援迴圈垃圾回收 一節。繼承
組:
Py_TPFLAGS_HAVE_GC
、tp_traverse
、tp_clear
Py_TPFLAGS_HAVE_GC
標誌位與tp_traverse
和tp_clear
欄位一起繼承,即如果子型別中Py_TPFLAGS_HAVE_GC
標誌位為清除狀態,並且子型別中的tp_traverse
和tp_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_Type
且tp_new
為 NULL,則此標誌會自動設定在 靜態型別 上。繼承
此標誌不被繼承。但是,子類將無法例項化,除非它們提供非 NULL 的
tp_new
(這隻能透過 C API 實現)。在 3.10 版本加入。
-
Py_TPFLAGS_MAPPING¶
此位表示當類的例項用作
match
塊的主題時,它們可能匹配對映模式。在註冊或子類化collections.abc.Mapping
時會自動設定,在註冊collections.abc.Sequence
時會自動清除。備註
Py_TPFLAGS_MAPPING
和Py_TPFLAGS_SEQUENCE
互斥;同時啟用這兩個標誌是錯誤的。繼承
此標誌由尚未設定
Py_TPFLAGS_SEQUENCE
的型別繼承。參見
PEP 634 – 結構化模式匹配:規範
在 3.10 版本加入。
-
Py_TPFLAGS_SEQUENCE¶
此位表示當類的例項用作
match
塊的主題時,它們可能匹配序列模式。在註冊或子類化collections.abc.Sequence
時會自動設定,在註冊collections.abc.Mapping
時會自動清除。備註
Py_TPFLAGS_MAPPING
和Py_TPFLAGS_SEQUENCE
互斥;同時啟用這兩個標誌是錯誤的。繼承
此標誌由尚未設定
Py_TPFLAGS_MAPPING
的型別繼承。參見
PEP 634 – 結構化模式匹配:規範
在 3.10 版本加入。
-
Py_TPFLAGS_VALID_VERSION_TAG¶
內部。不要設定或取消設定此標誌。要指示類已更改,請呼叫
PyType_Modified()
警告
此標誌存在於標頭檔案中,但未被使用。它將在 CPython 的未來版本中移除
-
Py_TPFLAGS_HEAPTYPE¶
-
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()
的 visit 和 arg 引數具有這些特定名稱;不要隨便命名它們。堆分配型別 的例項持有對其型別的引用。因此,它們的遍歷函式必須訪問
Py_TYPE(self)
,或者透過呼叫另一個堆分配型別(例如堆分配的超類)的tp_traverse
來委託此責任。如果它們不這樣做,則型別物件可能不會被垃圾回收。備註
tp_traverse
函式可以在任何執行緒中呼叫。在 3.9 版本中變更: 堆分配型別預計會在
tp_traverse
中訪問Py_TYPE(self)
。在早期版本的 Python 中,由於 bug 40217,這樣做可能導致子類崩潰。繼承
組:
Py_TPFLAGS_HAVE_GC
、tp_traverse
、tp_clear
此欄位由子型別與
tp_clear
和Py_TPFLAGS_HAVE_GC
標誌位一起繼承:如果子型別中的標誌位、tp_traverse
和tp_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_GC
、tp_traverse
、tp_clear
此欄位由子型別與
tp_traverse
和Py_TPFLAGS_HAVE_GC
標誌位一起繼承:如果子型別中的標誌位、tp_traverse
和tp_clear
都為零,則它們都從基型別繼承。參見
有關此槽位與其他槽位如何關聯的詳細資訊,請參閱物件生命週期。
-
richcmpfunc PyTypeObject.tp_richcompare¶
指向富比較函式的可選指標,其簽名為
PyObject *tp_richcompare(PyObject *self, PyObject *other, int op);
第一個引數保證是
PyTypeObject
定義的型別的例項。函式應返回比較結果(通常是
Py_True
或Py_False
)。如果比較未定義,則必須返回Py_NotImplemented
,如果發生其他錯誤,則必須返回NULL
並設定異常條件。定義了以下常量用於作為
tp_richcompare
和PyObject_RichCompare()
的第三個引數常量
比較
-
Py_LT¶
<
-
Py_LE¶
<=
-
Py_EQ¶
==
-
Py_NE¶
!=
-
Py_GT¶
>
-
Py_GE¶
>=
定義了以下宏以方便編寫富比較函式
-
Py_RETURN_RICHCOMPARE(VAL_A, VAL_B, op)¶
根據比較結果,從函式返回
Py_True
或Py_False
。VAL_A 和 VAL_B 必須可以透過 C 比較運算子進行排序(例如,它們可以是 C 整型或浮點型)。第三個引數指定了請求的操作,與PyObject_RichCompare()
類似。返回的值是一個新的 強引用。
出錯時,設定異常並從函式返回
NULL
。在 3.7 版本加入。
繼承
此欄位與
tp_hash
一起由子型別繼承:當子型別的tp_richcompare
和tp_hash
都為NULL
時,子型別會繼承tp_richcompare
和tp_hash
。預設
PyBaseObject_Type
提供了一個tp_richcompare
實現,它可以被繼承。但是,如果只定義了tp_hash
,則即使是繼承的函式也不會被使用,並且該型別的例項將無法參與任何比較。-
Py_LT¶
-
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()
獲取任意型別的字典。繼承
此欄位不被子型別繼承(儘管在此處定義的屬性透過不同的機制繼承)。
預設
如果此欄位為
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_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 引數是要初始化的例項;args 和 kwds 引數表示呼叫
__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 引數是要建立的物件的型別;args 和 kwds 引數表示呼叫該型別的位置引數和關鍵字引數。請注意,subtype 不必等於其
tp_new
函式被呼叫的型別;它可以是該型別的子型別(但不是不相關的型別)。tp_new
函式應呼叫subtype->tp_alloc(subtype, nitems)
為物件分配空間,然後只執行絕對必要的進一步初始化。可以安全地忽略或重複的初始化應放在tp_init
處理程式中。一個好的經驗法則是,對於不可變型別,所有初始化都應在tp_new
中進行,而對於可變型別,大部分初始化應推遲到tp_init
。設定
Py_TPFLAGS_DISALLOW_INSTANTIATION
標誌以禁止在 Python 中建立該型別的例項。繼承
此欄位由子型別繼承,但 靜態型別 不繼承此欄位,其
tp_base
為NULL
或&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 終結一個物件時,它會按以下演算法執行
Python 可能會將物件標記為 finalized。目前,Python 總是標記其型別支援垃圾回收(即
Py_TPFLAGS_HAVE_GC
標誌在tp_flags
中設定)的物件,並且從不標記其他型別的物件;這可能會在未來版本中改變。如果物件未標記為 finalized 且其
tp_finalize
終結器函式不為NULL
,則呼叫終結器函式。如果終結器函式被呼叫,並且終結器使物件可達(即,存在對物件的引用,並且它不是迴圈隔離的成員),則稱終結器已 resurrected 物件。關於終結器是否還可以透過向物件新增一個新的不使其可達的引用來複活物件,即物件(仍然)是迴圈隔離的成員,這是未指明的。
如果終結器復活了物件,則物件的待定銷燬被取消,並且如果存在,物件的 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 目前僅自動終結迴圈隔離的成員物件,但未來版本可能會在銷燬前定期終結物件。
要手動終結物件,不要直接呼叫此函式;請改用
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_vectorcall
為NULL
,則使用 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_new
和tp_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_item
和sq_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_length
為NULL
,則索引按原樣傳遞給函式。
-
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
槽進行數字就地乘法之後。
緩衝區物件結構¶
-
getbufferproc PyBufferProcs.bf_getbuffer¶
此函式的簽名是
int (PyObject *exporter, Py_buffer *view, int flags);
處理向 *exporter* 發出的請求,以按照 *flags* 的指定填充 *view*。除了第 (3) 點,此函式的實現必須採取以下步驟:
檢查請求是否可以滿足。如果不能,則丟擲
BufferError
,將 view->obj 設定為NULL
並返回-1
。填充請求的欄位。
遞增匯出數量的內部計數器。
將 view->obj 設定為 *exporter* 並遞增 view->obj。
返回
0
。
如果 *exporter* 是緩衝區提供者鏈或樹的一部分,可以使用兩種主要方案:
重新匯出:樹的每個成員都充當匯出物件,並將 view->obj 設定為自身的新的引用。
重定向:緩衝區請求被重定向到樹的根物件。在這裡,view->obj 將是對根物件的新引用。
*view* 的各個欄位在 緩衝區結構 一節中描述,匯出器必須如何響應特定請求的規則在 緩衝區請求型別 一節中。
Py_buffer
結構中指向的所有記憶體都屬於匯出器,並且必須保持有效,直到沒有消費者為止。format
、shape
、strides
、suboffsets
和internal
對消費者是隻讀的。PyBuffer_FillInfo()
提供了一種簡單的方法來公開簡單的位元組緩衝區,同時正確處理所有請求型別。PyObject_GetBuffer()
是包裝此函式的消費者介面。
-
releasebufferproc PyBufferProcs.bf_releasebuffer¶
此函式的簽名是
void (PyObject *exporter, Py_buffer *view);
處理釋放緩衝區資源的請求。如果不需要釋放任何資源,
PyBufferProcs.bf_releasebuffer
可以為NULL
。否則,此函式的標準實現將採取以下可選步驟:遞減匯出數量的內部計數器。
如果計數器為
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
設定為1
,ob_type
設定為型別引數。如果型別的tp_itemsize
非零,則物件的ob_size
欄位應初始化為 *nitems*,並且分配的記憶體塊的長度應為tp_basicsize + nitems*tp_itemsize
,向上舍入到sizeof(void*)
的倍數;否則,*nitems* 不使用,塊的長度應為tp_basicsize
。此函式不應執行任何其他例項初始化,甚至不應分配額外記憶體;這應由
tp_new
完成。
-
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 PyObject *(*iternextfunc)(PyObject*)¶
- 作為 穩定 ABI 的一部分。
請參閱
tp_iternext
。
-
typedef Py_ssize_t (*lenfunc)(PyObject*)¶
- 作為 穩定 ABI 的一部分。
-
typedef Py_ssize_t (*ssizeargfunc)(PyObject*, Py_ssize_t)¶
- 作為 穩定 ABI 的一部分。
-
typedef int (*ssizeobjargproc)(PyObject*, Py_ssize_t, 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 *),
};