型別物件¶
也許 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__ |
||
插槽 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/object.h
中找到。為了方便參考,這裡重複了其中找到的定義
typedef struct _typeobject {
PyObject_VAR_HEAD
const char *tp_name; /* For printing, in format "<module>.<name>" */
Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */
/* Methods to implement standard operations */
destructor tp_dealloc;
Py_ssize_t tp_vectorcall_offset;
getattrfunc tp_getattr;
setattrfunc tp_setattr;
PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2)
or tp_reserved (Python 3) */
reprfunc tp_repr;
/* Method suites for standard classes */
PyNumberMethods *tp_as_number;
PySequenceMethods *tp_as_sequence;
PyMappingMethods *tp_as_mapping;
/* More standard operations (here for binary compatibility) */
hashfunc tp_hash;
ternaryfunc tp_call;
reprfunc tp_str;
getattrofunc tp_getattro;
setattrofunc tp_setattro;
/* Functions to access object as input/output buffer */
PyBufferProcs *tp_as_buffer;
/* Flags to define presence of optional/expanded features */
unsigned long tp_flags;
const char *tp_doc; /* Documentation string */
/* Assigned meaning in release 2.0 */
/* call function for all accessible objects */
traverseproc tp_traverse;
/* delete references to contained objects */
inquiry tp_clear;
/* Assigned meaning in release 2.1 */
/* rich comparisons */
richcmpfunc tp_richcompare;
/* weak reference enabler */
Py_ssize_t tp_weaklistoffset;
/* Iterators */
getiterfunc tp_iter;
iternextfunc tp_iternext;
/* Attribute descriptor and subclassing stuff */
struct PyMethodDef *tp_methods;
struct PyMemberDef *tp_members;
struct PyGetSetDef *tp_getset;
// Strong reference on a heap type, borrowed reference on a static type
struct _typeobject *tp_base;
PyObject *tp_dict;
descrgetfunc tp_descr_get;
descrsetfunc tp_descr_set;
Py_ssize_t tp_dictoffset;
initproc tp_init;
allocfunc tp_alloc;
newfunc tp_new;
freefunc tp_free; /* Low-level free-memory routine */
inquiry tp_is_gc; /* For PyObject_IS_GC */
PyObject *tp_bases;
PyObject *tp_mro; /* method resolution order */
PyObject *tp_cache;
PyObject *tp_subclasses;
PyObject *tp_weaklist;
destructor tp_del;
/* Type attribute cache version tag. Added in version 2.6 */
unsigned int tp_version_tag;
destructor tp_finalize;
vectorcallfunc tp_vectorcall;
/* bitset of which type-watchers care about this type */
unsigned char tp_watched;
} PyTypeObject;
PyObject 插槽¶
型別物件結構擴充套件了 PyVarObject
結構。ob_size
欄位用於動態型別(由 type_new()
建立,通常從類語句中呼叫)。請注意,PyType_Type
(元型別)初始化 tp_itemsize
,這意味著它的例項(即型別物件)必須具有 ob_size
欄位。
-
Py_ssize_t PyObject.ob_refcnt¶
- 屬於 穩定 ABI 的一部分。
這是型別物件的引用計數,由
PyObject_HEAD_INIT
宏初始化為1
。請注意,對於靜態分配的型別物件,型別的例項(其ob_type
指回該型別的物件)不計入引用。但是,對於動態分配的型別物件,例項確實計入引用。繼承
此欄位不會被子型別繼承。
-
PyTypeObject *PyObject.ob_type¶
- 屬於 穩定 ABI 的一部分。
這是型別的型別,換句話說,是它的元型別。它由
PyObject_HEAD_INIT
宏的引數初始化,其值通常應為&PyType_Type
。但是,對於必須在 Windows (至少) 上可用的動態載入的擴充套件模組,編譯器會抱怨這不是一個有效的初始化程式。因此,約定是將NULL
傳遞給PyObject_HEAD_INIT
宏,並在模組初始化函式的開始處顯式初始化此欄位,然後再執行任何其他操作。這通常像這樣完成:Foo_Type.ob_type = &PyType_Type;
應該在建立型別的任何例項之前完成此操作。
PyType_Ready()
檢查ob_type
是否為NULL
,如果是,則將其初始化為基類的ob_type
欄位。PyType_Ready()
如果此欄位非零,則不會更改此欄位。繼承
此欄位被子型別繼承。
PyVarObject 槽¶
-
Py_ssize_t PyVarObject.ob_size¶
- 屬於 穩定 ABI 的一部分。
對於靜態分配的型別物件,此欄位應初始化為零。對於動態分配的型別物件,此欄位具有特殊的內部含義。
繼承
此欄位不會被子型別繼承。
PyTypeObject 槽¶
每個槽都有一個描述繼承的部分。如果 PyType_Ready()
可以在欄位設定為 NULL
時設定一個值,則還會有一個“預設”部分。(請注意,在 PyBaseObject_Type
和 PyType_Type
上設定的許多欄位實際上充當預設值。)
-
const char *PyTypeObject.tp_name¶
指向一個以 NULL 結尾的字串的指標,其中包含型別的名稱。對於作為模組全域性變數訪問的型別,該字串應該是完整的模組名稱,後跟一個點,後跟型別名稱;對於內建型別,它應該只是型別名稱。如果模組是包的子模組,則完整的包名稱是完整模組名稱的一部分。例如,在包
P
中的子包Q
中的模組M
中定義的名為T
的型別應具有tp_name
初始化器"P.Q.M.T"
。對於動態分配的型別物件,這應該只是型別名稱,模組名稱顯式儲存在型別字典中,作為鍵
'__module__'
的值。對於靜態分配的型別物件,tp_name 欄位應包含一個點。最後一個點之前的所有內容都可以作為
__module__
屬性訪問,最後一個點之後的所有內容都可以作為__name__
屬性訪問。如果不存在點,則整個
tp_name
欄位可以作為__name__
屬性訪問,並且__module__
屬性是未定義的(除非如上所述在字典中顯式設定)。這意味著您的型別將無法 pickle。此外,它不會列在用 pydoc 建立的模組文件中。此欄位不能為
NULL
。它是PyTypeObject()
中唯一必需的欄位(可能除了tp_itemsize
之外)。繼承
此欄位不會被子型別繼承。
-
Py_ssize_t PyTypeObject.tp_basicsize¶
-
Py_ssize_t PyTypeObject.tp_itemsize¶
這些欄位允許計算型別例項的大小(以位元組為單位)。
有兩種型別的型別:具有固定長度例項的型別具有零
tp_itemsize
欄位,具有可變長度例項的型別具有非零tp_itemsize
欄位。對於具有固定長度例項的型別,所有例項都具有相同的大小,在tp_basicsize
中給出。對於具有可變長度例項的型別,例項必須具有
ob_size
欄位,並且例項大小為tp_basicsize
加上 N 乘以tp_itemsize
,其中 N 是物件的“長度”。 N 的值通常儲存在例項的ob_size
欄位中。但也存在例外:例如,整數使用負的ob_size
來表示負數,而 N 在那裡是abs(ob_size)
。此外,例項佈局中存在ob_size
欄位並不意味著例項結構是可變長度的(例如,列表型別的結構具有固定長度的例項,但這些例項具有有意義的ob_size
欄位)。基本大小包括由宏
PyObject_HEAD
或PyObject_VAR_HEAD
(無論使用哪個來宣告例項結構)宣告的例項中的欄位,這反過來包括_ob_prev
和_ob_next
欄位(如果它們存在)。這意味著獲取tp_basicsize
的初始值的唯一正確方法是對用於宣告例項佈局的結構使用sizeof
運算子。基本大小不包括 GC 標頭大小。關於對齊的說明:如果可變項需要特定的對齊方式,則應由
tp_basicsize
的值來處理。示例:假設一個型別實現了一個double
陣列。tp_itemsize
是sizeof(double)
。程式設計師有責任確保tp_basicsize
是sizeof(double)
的倍數(假設這是double
的對齊要求)。對於任何具有可變長度例項的型別,此欄位不能為
NULL
。繼承
這些欄位由子型別單獨繼承。如果基型別具有非零的
tp_itemsize
,通常在子型別中將tp_itemsize
設定為不同的非零值是不安全的(儘管這取決於基型別的實現)。
-
destructor PyTypeObject.tp_dealloc¶
指向例項解構函式的指標。除非型別保證其例項永遠不會被釋放(如單例
None
和Ellipsis
的情況),否則必須定義此函式。函式簽名是void tp_dealloc(PyObject *self);
當新的引用計數為零時,解構函式由
Py_DECREF()
和Py_XDECREF()
宏呼叫。此時,例項仍然存在,但沒有對它的引用。解構函式應釋放例項擁有的所有引用,釋放例項擁有的所有記憶體緩衝區(使用與用於分配緩衝區的分配函式相對應的釋放函式),並呼叫型別的tp_free
函式。如果型別不可子型別化(沒有設定Py_TPFLAGS_BASETYPE
標誌位),則可以直接呼叫物件釋放器,而不是透過tp_free
。物件釋放器應該是用於分配例項的釋放器;如果例項是使用PyObject_New
或PyObject_NewVar
分配的,則通常為PyObject_Del()
;如果例項是使用PyObject_GC_New
或PyObject_GC_NewVar
分配的,則為PyObject_GC_Del()
。如果該型別支援垃圾回收(已設定
Py_TPFLAGS_HAVE_GC
標誌位),則解構函式應在清除任何成員欄位之前呼叫PyObject_GC_UnTrack()
。static void foo_dealloc(foo_object *self) { PyObject_GC_UnTrack(self); Py_CLEAR(self->ref); Py_TYPE(self)->tp_free((PyObject *)self); }
最後,如果該型別是堆分配的 (
Py_TPFLAGS_HEAPTYPE
),則釋放器應在呼叫型別釋放器之後(透過Py_DECREF()
)釋放對其型別物件擁有的引用。為了避免懸空指標,推薦的實現方法是static void foo_dealloc(foo_object *self) { PyTypeObject *tp = Py_TYPE(self); // free references and buffers here tp->tp_free(self); Py_DECREF(tp); }
警告
在垃圾回收的 Python 中,
tp_dealloc
可以從任何 Python 執行緒呼叫,而不僅僅是建立物件的執行緒(如果物件成為引用計數迴圈的一部分,則該迴圈可能由任何執行緒上的垃圾回收收集)。對於 Python API 呼叫來說,這不是問題,因為呼叫tp_dealloc
的執行緒將擁有全域性直譯器鎖 (GIL)。但是,如果正在銷燬的物件反過來又銷燬了來自其他 C 或 C++ 庫的物件,則應注意確保在呼叫tp_dealloc
的執行緒上銷燬這些物件不會違反庫的任何假設。繼承
此欄位被子型別繼承。
-
Py_ssize_t PyTypeObject.tp_vectorcall_offset¶
一個可選的偏移量,指向實現使用 vectorcall 協議 呼叫物件的每個例項的函式,這是更簡單的
tp_call
的更高效替代方案。只有當設定了
Py_TPFLAGS_HAVE_VECTORCALL
標誌時,才使用此欄位。如果設定了該標誌,則該值必須是一個正整數,其中包含例項中vectorcallfunc
指標的偏移量。vectorcallfunc 指標可以為
NULL
,在這種情況下,例項的行為就好像沒有設定Py_TPFLAGS_HAVE_VECTORCALL
一樣:呼叫例項將回退到tp_call
。任何設定
Py_TPFLAGS_HAVE_VECTORCALL
的類還必須設定tp_call
,並確保其行為與 vectorcallfunc 函式一致。這可以透過將 tp_call 設定為PyVectorcall_Call()
來完成。在 3.8 版本中更改: 在 3.8 版本之前,此槽名為
tp_print
。在 Python 2.x 中,它用於列印到檔案。在 Python 3.0 到 3.7 中,它未使用。在 3.12 版本中更改: 在 3.12 版本之前,不建議 可變堆型別 實現 vectorcall 協議。當用戶在 Python 程式碼中設定
__call__
時,只會更新 tp_call,這可能會導致它與 vectorcall 函式不一致。自 3.12 版本以來,設定__call__
將透過清除Py_TPFLAGS_HAVE_VECTORCALL
標誌來停用 vectorcall 最佳化。繼承
此欄位始終被繼承。但是,
Py_TPFLAGS_HAVE_VECTORCALL
標誌並不總是被繼承。如果未設定該標誌,則子類將不會使用 vectorcall,除非顯式呼叫PyVectorcall_Call()
。
-
getattrfunc PyTypeObject.tp_getattr¶
一個可選的指向獲取屬性字串函式的指標。
此欄位已棄用。當它被定義時,它應該指向一個功能與
tp_getattro
函式相同,但使用 C 字串而不是 Python 字串物件來給出屬性名稱的函式。繼承
此欄位與
tp_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
將導致tp_hash
插槽設定為PyObject_HashNotImplemented()
。繼承
此欄位與
tp_richcompare
一起被子型別繼承:當子型別的tp_richcompare
和tp_hash
都為NULL
時,子型別將同時繼承tp_richcompare
和tp_hash
。預設
PyBaseObject_Type
使用PyObject_GenericHash()
。
-
ternaryfunc PyTypeObject.tp_call¶
一個可選的函式指標,用於實現呼叫物件。如果物件不可呼叫,則應為
NULL
。其簽名與PyObject_Call()
相同。PyObject *tp_call(PyObject *self, PyObject *args, PyObject *kwargs);
繼承
此欄位被子型別繼承。
-
reprfunc PyTypeObject.tp_str¶
一個可選的函式指標,用於實現內建操作
str()
。(請注意,現在str
是一種型別,而str()
呼叫該型別的建構函式。此建構函式呼叫PyObject_Str()
來完成實際工作,而PyObject_Str()
將呼叫此處理程式。)其簽名與
PyObject_Str()
相同。PyObject *tp_str(PyObject *self);
該函式必須返回字串或 Unicode 物件。 它應該是物件的“友好”字串表示形式,因為這是
print()
函式等將使用的表示形式。繼承
此欄位被子型別繼承。
預設
當此欄位未設定時,將呼叫
PyObject_Repr()
返回字串表示形式。
-
getattrofunc PyTypeObject.tp_getattro¶
一個可選的獲取屬性函式指標。
其簽名與
PyObject_GetAttr()
相同。PyObject *tp_getattro(PyObject *self, PyObject *attr);
通常將其設定為
PyObject_GenericGetAttr()
很方便,它實現了查詢物件屬性的正常方法。繼承
此欄位與
tp_getattr
一起被子型別繼承:當子型別的tp_getattr
和tp_getattro
都為NULL
時,子型別將從其基型別同時繼承tp_getattr
和tp_getattro
。預設
PyBaseObject_Type
使用PyObject_GenericGetAttr()
。
-
setattrofunc PyTypeObject.tp_setattro¶
一個可選的指向設定和刪除屬性的函式的指標。
其簽名與
PyObject_SetAttr()
相同。int tp_setattro(PyObject *self, PyObject *attr, PyObject *value);
此外,必須支援將value 設定為
NULL
來刪除屬性。 通常,將其設定為PyObject_GenericSetAttr()
很方便,它實現了設定物件屬性的正常方法。繼承
此欄位與
tp_setattr
一起被子型別繼承:當子型別的tp_setattr
和tp_setattro
都為NULL
時,子型別將從其基型別同時繼承tp_setattr
和tp_setattro
。預設
PyBaseObject_Type
使用PyObject_GenericSetAttr()
。
-
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
值。 .. XXX 大多數標誌位真的是單獨繼承的嗎?預設
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¶
當物件支援垃圾回收時,會設定此位。如果設定了此位,則必須使用
PyObject_GC_New
建立例項,並使用PyObject_GC_Del()
銷燬例項。 更多資訊請參見支援迴圈垃圾回收部分。此位還意味著型別物件中存在與 GC 相關的欄位tp_traverse
和tp_clear
。繼承
組:
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¶
此位表示該類的例項具有 ~object.__dict__ 屬性,並且字典的空間由虛擬機器管理。
如果設定了此標誌,則還應設定
Py_TPFLAGS_HAVE_GC
。型別遍歷函式必須呼叫
PyObject_VisitManagedDict()
,並且其清除函式必須呼叫PyObject_ClearManagedDict()
。3.12 版本新增。
繼承
除非在超類中設定了
tp_dictoffset
欄位,否則此標誌會被繼承。
-
Py_TPFLAGS_MANAGED_WEAKREF¶
此位表示該類的例項應該是可弱引用的。
3.12 版本新增。
繼承
除非在超類中設定了
tp_weaklistoffset
欄位,否則此標誌會被繼承。
-
Py_TPFLAGS_ITEMS_AT_END¶
僅可用於可變大小的型別,即具有非零
tp_itemsize
的型別。表示此型別的例項的可變大小部分位於例項記憶體區域的末尾,偏移量為
Py_TYPE(obj)->tp_basicsize
(在每個子類中可能不同)。設定此標誌時,請確保所有超類都使用此記憶體佈局,或者都不是可變大小的。Python 不會對此進行檢查。
3.12 版本新增。
繼承
此標誌會被繼承。
-
Py_TPFLAGS_LONG_SUBCLASS¶
-
Py_TPFLAGS_LIST_SUBCLASS¶
-
Py_TPFLAGS_TUPLE_SUBCLASS¶
-
Py_TPFLAGS_BYTES_SUBCLASS¶
-
Py_TPFLAGS_UNICODE_SUBCLASS¶
-
Py_TPFLAGS_DICT_SUBCLASS¶
-
Py_TPFLAGS_BASE_EXC_SUBCLASS¶
-
Py_TPFLAGS_TYPE_SUBCLASS¶
這些標誌被諸如
PyLong_Check()
之類的函式用來快速確定型別是否是內建型別的子類;這種特定的檢查比像PyObject_IsInstance()
這樣的通用檢查更快。從內建型別繼承的自定義型別應適當設定其tp_flags
,否則與此類型別互動的程式碼將根據使用的檢查型別而表現不同。
-
Py_TPFLAGS_HAVE_FINALIZE¶
當型別結構中存在
tp_finalize
插槽時,將設定此位。3.4 版本新增。
3.8 版本起已棄用: 此標誌不再必要,因為直譯器假定型別結構中始終存在
tp_finalize
插槽。
-
Py_TPFLAGS_HAVE_VECTORCALL¶
當類實現 vectorcall 協議時,將設定此位。 有關詳細資訊,請參見
tp_vectorcall_offset
。繼承
如果也繼承了
tp_call
,則會繼承此位。3.9 版本新增。
在 3.12 版本中變更: 當重新分配類的
__call__()
方法時,現在會從類中刪除此標誌。現在,可變類可以繼承此標誌。
-
Py_TPFLAGS_IMMUTABLETYPE¶
對於不可變的型別物件,會設定此位:不能設定或刪除型別屬性。
PyType_Ready()
會自動將此標誌應用於靜態型別。繼承
此標誌不會被繼承。
3.10 版本新增。
-
Py_TPFLAGS_DISALLOW_INSTANTIATION¶
禁止建立該型別的例項:將
tp_new
設定為 NULL,並且不在型別字典中建立__new__
鍵。該標誌必須在建立型別之前設定,而不是之後。例如,它必須在對該型別呼叫
PyType_Ready()
之前設定。如果
tp_base
為 NULL 或&PyBaseObject_Type
並且tp_new
為 NULL,則會在靜態型別上自動設定該標誌。繼承
此標誌不會被繼承。但是,除非子類提供非 NULL 的
tp_new
(這隻能透過 C API 實現),否則子類將不可例項化。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(localobject *self, visitproc visit, void *arg) { Py_VISIT(self->args); Py_VISIT(self->kw); Py_VISIT(self->dict); return 0; }
請注意,
Py_VISIT()
僅在那些可以參與引用迴圈的成員上呼叫。儘管還有一個self->key
成員,但它只能是NULL
或 Python 字串,因此不能成為引用迴圈的一部分。另一方面,即使您知道某個成員永遠不會成為迴圈的一部分,作為除錯輔助手段,您可能仍然希望訪問它,以便
gc
模組的get_referents()
函式會包含它。堆型別(
Py_TPFLAGS_HEAPTYPE
)必須使用Py_VISIT(Py_TYPE(self));
這僅在 Python 3.9 中需要。為了支援 Python 3.8 及更早的版本,此行必須是條件性的
#if PY_VERSION_HEX >= 0x03090000 Py_VISIT(Py_TYPE(self)); #endif
如果在
tp_flags
欄位中設定了Py_TPFLAGS_MANAGED_DICT
位,則 traverse 函式必須像這樣呼叫PyObject_VisitManagedDict()
PyObject_VisitManagedDict((PyObject*)self, visit, arg);
警告
在實現
tp_traverse
時,只需要訪問例項擁有(透過對它們具有強引用)的成員。例如,如果一個物件透過tp_weaklist
插槽支援弱引用,則支援連結串列的指標(tp_weaklist 指向的指標)必須不被訪問,因為該例項不直接擁有對其自身的弱引用(弱引用列表是為了支援弱引用機制,但例項對其中的元素沒有強引用,因為即使例項仍然存在,也允許刪除它們)。請注意,
Py_VISIT()
要求local_traverse()
的 *visit* 和 *arg* 引數具有這些特定的名稱;不要隨意命名它們。堆分配型別 的例項保持對其型別的引用。因此,它們的遍歷函式必須訪問
Py_TYPE(self)
,或者透過呼叫另一個堆分配型別(例如堆分配的超類)的tp_traverse
來委派此責任。如果它們不這樣做,則型別物件可能無法被垃圾回收。在 3.9 版本中更改: 堆分配型別應在
tp_traverse
中訪問Py_TYPE(self)
。在早期版本的 Python 中,由於 錯誤 40217,這樣做可能會導致子類崩潰。繼承
組:
Py_TPFLAGS_HAVE_GC
,tp_traverse
,tp_clear
此欄位與
tp_clear
和Py_TPFLAGS_HAVE_GC
標誌位一起被子型別繼承:如果子型別中所有位都為零,則標誌位、tp_traverse
和tp_clear
都從基型別繼承。
-
inquiry PyTypeObject.tp_clear¶
一個可選的指向垃圾收集器的清除函式的指標。僅當設定了
Py_TPFLAGS_HAVE_GC
標誌位時才使用。其簽名為int tp_clear(PyObject *);
tp_clear
成員函式用於在垃圾收集器檢測到的迴圈垃圾中打破引用迴圈。綜合來看,系統中所有的tp_clear
函式必須組合起來以打破所有引用迴圈。這很微妙,如果有任何疑問,請提供tp_clear
函式。例如,元組型別不實現tp_clear
函式,因為可以證明沒有任何引用迴圈可以完全由元組組成。因此,其他型別的tp_clear
函式必須足以打破任何包含元組的迴圈。這並不是顯而易見的,而且很少有很好的理由避免實現tp_clear
。tp_clear
的實現應該刪除例項對其可能是 Python 物件的成員的引用,並將指向這些成員的指標設定為NULL
,如下例所示static int local_clear(localobject *self) { Py_CLEAR(self->key); Py_CLEAR(self->args); Py_CLEAR(self->kw); Py_CLEAR(self->dict); return 0; }
應該使用
Py_CLEAR()
宏,因為清除引用很微妙:在將指向包含物件的指標設定為NULL
之後,才能釋放(透過Py_DECREF()
)對包含物件的引用。這是因為釋放引用可能會導致包含的物件變成垃圾,從而觸發一系列回收活動,其中可能包括呼叫任意 Python 程式碼(由於與包含物件關聯的終結器或弱引用回撥)。如果此類程式碼有可能再次引用 self,那麼重要的是,此時指向包含物件的指標為NULL
,以便 self 知道不能再使用包含的物件。Py_CLEAR()
宏以安全的順序執行操作。如果在
tp_flags
欄位中設定了Py_TPFLAGS_MANAGED_DICT
位,則遍歷函式必須像這樣呼叫PyObject_ClearManagedDict()
PyObject_ClearManagedDict((PyObject*)self);
請注意,
tp_clear
並非總是在例項被釋放之前呼叫。例如,當引用計數足以確定不再使用物件時,不會涉及迴圈垃圾收集器,而是直接呼叫tp_dealloc
。由於
tp_clear
函式的目標是打破引用迴圈,因此沒有必要清除像 Python 字串或 Python 整數這樣的包含物件,因為它們不能參與引用迴圈。另一方面,清除所有包含的 Python 物件可能很方便,並編寫型別的tp_dealloc
函式來呼叫tp_clear
。關於 Python 垃圾回收方案的更多資訊,請參見 支援迴圈垃圾回收 部分。
繼承
組:
Py_TPFLAGS_HAVE_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 不支援。在這方面,兩個編譯器都嚴格符合標準。因此,應在擴充套件模組的 init 函式中設定
tp_base
。繼承
此欄位不會被子型別繼承(顯然)。
預設
此欄位的預設值為
&PyBaseObject_Type
(Python 程式設計師將其稱為型別object
)。
-
PyObject *PyTypeObject.tp_dict¶
型別的字典由
PyType_Ready()
儲存在此處。在呼叫 PyType_Ready 之前,此欄位通常應初始化為
NULL
;它也可以初始化為包含型別初始屬性的字典。一旦PyType_Ready()
初始化了型別,則只有當它們不對應於過載操作(如__add__()
)時,才可以將型別的額外屬性新增到此字典中。一旦完成型別的初始化,此欄位應被視為只讀。某些型別可能不會將它們的字典儲存在此槽中。使用
PyType_GetDict()
檢索任意型別的字典。3.12 版本中的更改: 內部細節:對於靜態內建型別,這始終為
NULL
。相反,此類型別的字典儲存在PyInterpreterState
上。使用PyType_GetDict()
獲取任意型別的字典。繼承
此欄位不會被子型別繼承(儘管此處定義的屬性是透過不同的機制繼承的)。
預設
如果此欄位為
NULL
,則PyType_Ready()
將為其分配一個新字典。警告
使用
PyDict_SetItem()
或以其他方式透過字典 C-API 修改tp_dict
是不安全的。
-
descrgetfunc PyTypeObject.tp_descr_get¶
指向“描述符獲取”函式的可選指標。
函式簽名是
PyObject * tp_descr_get(PyObject *self, PyObject *obj, PyObject *type);
繼承
此欄位被子型別繼承。
-
descrsetfunc PyTypeObject.tp_descr_set¶
一個可選的函式指標,用於設定和刪除描述符的值。
函式簽名是
int tp_descr_set(PyObject *self, PyObject *obj, PyObject *value);
value 引數設定為
NULL
以刪除值。繼承
此欄位被子型別繼承。
-
Py_ssize_t PyTypeObject.tp_dictoffset¶
雖然仍然支援此欄位,但如果可能,應使用
Py_TPFLAGS_MANAGED_DICT
。如果此型別的例項具有包含例項變數的字典,則此欄位為非零值,幷包含該型別例項中例項變數字典的偏移量;此偏移量由
PyObject_GenericGetAttr()
使用。不要將此欄位與
tp_dict
混淆;那是型別物件本身屬性的字典。該值指定字典相對於例項結構起始位置的偏移量。
tp_dictoffset
應被視為只寫。要獲取指向字典的指標,請呼叫PyObject_GenericGetDict()
。呼叫PyObject_GenericGetDict()
可能需要為字典分配記憶體,因此在訪問物件上的屬性時,呼叫PyObject_GetAttr()
可能更有效率。同時設定
Py_TPFLAGS_MANAGED_WEAKREF
位和tp_dictoffset
是錯誤的。繼承
此欄位由子型別繼承。子型別不應覆蓋此偏移量;如果 C 程式碼嘗試在前一個偏移量處訪問字典,這樣做可能不安全。為了正確支援繼承,請使用
Py_TPFLAGS_MANAGED_DICT
。預設
此槽沒有預設值。對於靜態型別,如果該欄位為
NULL
,則不會為例項建立__dict__
。如果
Py_TPFLAGS_MANAGED_DICT
位在tp_flags
欄位中設定,則tp_dictoffset
將設定為-1
,以指示使用此欄位是不安全的。
-
initproc PyTypeObject.tp_init¶
指向例項初始化函式的可選指標。
此函式對應於類的
__init__()
方法。與__init__()
類似,可以在不呼叫__init__()
的情況下建立例項,並且可以透過再次呼叫其__init__()
方法來重新初始化例項。函式簽名是
int tp_init(PyObject *self, PyObject *args, PyObject *kwds);
self 引數是要初始化的例項;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);
繼承
此欄位由靜態子型別繼承,但不由動態子型別(由 class 語句建立的子型別)繼承。
預設
對於動態子型別,此欄位始終設定為
PyType_GenericAlloc()
,以強制執行標準堆分配策略。對於靜態子型別,
PyBaseObject_Type
使用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);
與此簽名相容的初始化程式是
PyObject_Free()
。繼承
此欄位由靜態子型別繼承,但不由動態子型別(由 class 語句建立的子型別)繼承
預設
在動態子型別中,此欄位設定為一個合適的釋放器,以便與
PyType_GenericAlloc()
以及Py_TPFLAGS_HAVE_GC
標誌位的取值相匹配。對於靜態子型別,
PyBaseObject_Type
使用PyObject_Del()
。
-
inquiry PyTypeObject.tp_is_gc¶
一個可選的函式指標,由垃圾回收器呼叫。
垃圾回收器需要知道一個特定的物件是否是可回收的。通常,檢視物件的型別
tp_flags
欄位並檢查Py_TPFLAGS_HAVE_GC
標誌位就足夠了。但是,某些型別具有靜態和動態分配的例項的混合,並且靜態分配的例項是不可回收的。此類型別應定義此函式;對於可回收的例項,它應返回1
,對於不可回收的例項,則返回0
。其簽名是int tp_is_gc(PyObject *self);
(唯一的例子是型別本身。元型別
PyType_Type
定義了此函式來區分靜態分配的型別和動態分配的型別。)繼承
此欄位被子型別繼承。
預設
此槽沒有預設值。如果此欄位為
NULL
,則使用Py_TPFLAGS_HAVE_GC
作為功能等效項。
-
PyObject *PyTypeObject.tp_bases¶
基型別的元組。
此欄位應設定為
NULL
並視為只讀。當型別初始化
時,Python 將填充它。對於動態建立的類,可以使用
Py_tp_bases
槽
來代替PyType_FromSpecWithBases()
的 bases 引數。首選引數形式。警告
多重繼承對於靜態定義的型別效果不佳。如果將
tp_bases
設定為元組,Python 不會引發錯誤,但是某些槽將僅從第一個基類繼承。繼承
此欄位不被繼承。
-
PyObject *PyTypeObject.tp_mro¶
包含擴充套件的基型別集的元組,從型別本身開始,以
object
結束,按照方法解析順序排列。此欄位應設定為
NULL
並視為只讀。當型別初始化
時,Python 將填充它。繼承
此欄位不被繼承;它由
PyType_Ready()
重新計算。
-
PyObject *PyTypeObject.tp_cache¶
未使用。僅供內部使用。
繼承
此欄位不被繼承。
-
void *PyTypeObject.tp_subclasses¶
子類的集合。僅供內部使用。可能是一個無效的指標。
要獲取子類的列表,請呼叫 Python 方法
__subclasses__()
。在 3.12 版本中變更: 對於某些型別,此欄位不儲存有效的 PyObject*。該型別已更改為 void* 以指示這一點。
繼承
此欄位不被繼承。
-
PyObject *PyTypeObject.tp_weaklist¶
弱引用列表頭,用於對此型別物件的弱引用。不被繼承。僅供內部使用。
在 3.12 版本中變更:內部細節:對於靜態內建型別,即使添加了弱引用,這也始終為
NULL
。相反,每個弱引用都儲存在PyInterpreterState
上。使用公共 C-API 或內部_PyObject_GET_WEAKREFS_LISTPTR()
宏以避免區分。繼承
此欄位不被繼承。
-
destructor PyTypeObject.tp_del¶
此欄位已棄用。請改用
tp_finalize
。
-
unsigned int PyTypeObject.tp_version_tag¶
用於索引到方法快取中。僅供內部使用。
繼承
此欄位不被繼承。
-
destructor PyTypeObject.tp_finalize¶
一個指向例項終結函式的可選指標。其簽名是
void tp_finalize(PyObject *self);
如果設定了
tp_finalize
,則直譯器在終結例項時會呼叫它一次。它要麼從垃圾回收器呼叫(如果例項是孤立引用迴圈的一部分),要麼在物件被釋放之前呼叫。無論哪種方式,都保證在嘗試打破引用迴圈之前呼叫它,從而確保它找到處於正常狀態的物件。tp_finalize
不應改變當前的異常狀態;因此,編寫非平凡終結器的推薦方法是static void local_finalize(PyObject *self) { PyObject *error_type, *error_value, *error_traceback; /* Save the current exception, if any. */ PyErr_Fetch(&error_type, &error_value, &error_traceback); /* ... */ /* Restore the saved exception. */ PyErr_Restore(error_type, error_value, error_traceback); }
繼承
此欄位被子型別繼承。
3.4 版本新增。
在 3.8 版本中變更:在 3.8 版本之前,必須設定
Py_TPFLAGS_HAVE_FINALIZE
標誌位才能使用此欄位。現在不再需要這樣做。另請參閱
“安全物件終結”(PEP 442)
-
vectorcallfunc PyTypeObject.tp_vectorcall¶
用於此型別物件呼叫的向量呼叫函式。換句話說,它用於為
type.__call__
實現 向量呼叫。如果tp_vectorcall
為NULL
,則使用__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¶
-
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 *(*iternextfunc)(PyObject*)¶
- 屬於 穩定 ABI 的一部分。
請參閱
tp_iternext
。
-
typedef Py_ssize_t (*lenfunc)(PyObject*)¶
- 屬於 穩定 ABI 的一部分。
-
typedef PyObject *(*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 *),
};