Python 型別與 C 結構#
在 C 程式碼中定義了幾個新的型別。其中大部分可以從 Python 存取,但少數由於用途有限而未公開。每個新的 Python 型別都有一個關聯的 PyObject* 具有一個內部結構,包含一個指向「方法表」的指標,該表定義了新物件在 Python 中的行為方式。當你在 C 程式碼中接收到一個 Python 物件時,你總是會得到一個指向 PyObject
結構的指標。因為 PyObject
結構非常通用,且僅定義了 PyObject_HEAD
,它本身並沒有太大的意義。然而,不同的物件在 PyObject_HEAD
之後包含更多細節(但你必須轉換為正確的型別才能存取它們 — 或者使用存取器函數或巨集)。
定義的新 Python 型別#
Python 型別在 C 語言中與 Python 中的類別功能相當。透過建構一個新的 Python 型別,你可以為 Python 提供一個新的物件。ndarray 物件是在 C 語言中定義的新型別的一個例子。新型別在 C 語言中透過兩個基本步驟定義
建立一個 C 結構(通常命名為
Py{Name}Object
),該結構與PyObject
結構本身二進位相容,但包含該特定物件所需的額外資訊;使用指向實作該型別所需行為的函數的指標來填充
PyTypeObject
表格(由PyObject
結構的 ob_type 成員指向)。
與其使用定義 Python 類別行為的特殊方法名稱,不如使用「函數表」,它指向實作所需結果的函數。自 Python 2.2 以來,PyTypeObject 本身已變得動態,這允許 C 型別可以從 C 語言中的其他 C 型別「子型別化」,並在 Python 中子類別化。子型別繼承來自其父型別的屬性和方法。
有兩個主要的新型別:ndarray ( PyArray_Type
) 和 ufunc ( PyUFunc_Type
)。其他型別扮演輔助角色:PyArrayIter_Type
、PyArrayMultiIter_Type
和 PyArrayDescr_Type
。PyArrayIter_Type
是 ndarray 的扁平迭代器的型別(當取得 flat 屬性時返回的物件)。PyArrayMultiIter_Type
是呼叫 broadcast
時返回的物件的型別。它處理對巢狀序列集合的迭代和廣播。此外,PyArrayDescr_Type
是資料型別描述符型別,其實例描述資料,而 PyArray_DTypeMeta
是資料型別描述符的中繼類別。還有新的純量陣列型別,它們是與陣列可用的每個基本資料型別對應的新 Python 純量。其他型別是佔位符,允許陣列純量適合實際 Python 型別的層次結構中。最後,與 NumPy 內建資料型別對應的 PyArray_DTypeMeta
實例也是公開可見的。
PyArray_Type 和 PyArrayObject#
-
PyTypeObject PyArray_Type#
ndarray 的 Python 型別是
PyArray_Type
。在 C 語言中,每個 ndarray 都是指向PyArrayObject
結構的指標。此結構的 ob_type 成員包含指向PyArray_Type
型別物件的指標。
-
type PyArrayObject#
-
type NPY_AO#
PyArrayObject
C 結構包含陣列所需的所有資訊。ndarray(及其子類別)的所有實例都將具有此結構。為了未來的相容性,通常應使用提供的巨集來存取這些結構成員。如果你需要一個較短的名稱,那麼你可以使用NPY_AO
(已棄用),它被定義為等同於PyArrayObject
。直接存取結構欄位已被棄用。請改用PyArray_*(arr)
形式。從 NumPy 1.20 開始,此結構的大小不被視為 NumPy ABI 的一部分(請參閱成員列表末尾的註解)。typedef struct PyArrayObject { PyObject_HEAD char *data; int nd; npy_intp *dimensions; npy_intp *strides; PyObject *base; PyArray_Descr *descr; int flags; PyObject *weakreflist; /* version dependent private members */ } PyArrayObject;
PyObject_HEAD
所有 Python 物件都需要這個。它由(至少)一個參考計數成員(
ob_refcnt
)和一個指向型別物件(ob_type
)的指標組成。(如果 Python 是使用特殊選項編譯的,也可能存在其他元素,詳情請參閱 Python 原始碼樹中的 Include/object.h)。ob_type 成員指向一個 Python 型別物件。
-
char *data#
可透過
PyArray_DATA
存取,此資料成員是指向陣列第一個元素的指標。此指標可以(且通常應該)被重新轉換為陣列的資料型別。
-
int nd#
一個整數,提供此陣列的維度數量。當 nd 為 0 時,陣列有時被稱為 rank-0 陣列。這樣的陣列具有未定義的維度和步幅,無法存取。在
ndarraytypes.h
中定義的巨集PyArray_NDIM
指向此資料成員。NPY_MAXDIMS
被定義為限制維度數量的編譯時間常數。這個數字自 NumPy 2 以來是 64,之前是 32。然而,我們可能希望在未來移除此限制,因此對於依賴此上限的程式碼,最好明確檢查維度。
-
npy_intp *dimensions#
一個整數陣列,只要 nd \(\geq\) 1,就提供每個維度的形狀。整數始終足夠大以容納平台上的指標,因此維度大小僅受記憶體限制。
PyArray_DIMS
是與此資料成員關聯的巨集。
-
npy_intp *strides#
一個整數陣列,為每個維度提供必須跳過的位元組數,才能到達該維度中的下一個元素。與巨集
PyArray_STRIDES
關聯。
-
PyObject *base#
由
PyArray_BASE
指向,此成員用於保存指向另一個與此陣列相關的 Python 物件的指標。有兩種使用情況如果此陣列不擁有自己的記憶體,則 base 指向擁有它的 Python 物件(可能是另一個陣列物件)
如果此陣列設定了
NPY_ARRAY_WRITEBACKIFCOPY
旗標,則此陣列是「行為不當」陣列的工作副本。
當呼叫
PyArray_ResolveWritebackIfCopy
時,base 指向的陣列將使用此陣列的內容更新。
-
PyArray_Descr *descr#
指向資料型別描述符物件的指標(見下文)。資料型別描述符物件是新型內建型別的實例,它允許對記憶體進行通用描述。每個支援的資料型別都有一個描述符結構。此描述符結構包含有關型別的有用資訊,以及指向函數指標表的指標,以實作特定功能。顧名思義,它與巨集
PyArray_DESCR
關聯。
-
int flags#
由巨集
PyArray_FLAGS
指向,此資料成員表示旗標,指示如何解釋資料指向的記憶體。可能的旗標有NPY_ARRAY_C_CONTIGUOUS
、NPY_ARRAY_F_CONTIGUOUS
、NPY_ARRAY_OWNDATA
、NPY_ARRAY_ALIGNED
、NPY_ARRAY_WRITEABLE
、NPY_ARRAY_WRITEBACKIFCOPY
。
註記
其他成員被視為私有且與版本相關。如果結構的大小對你的程式碼很重要,則必須特別注意。當這相關時,一個可能的使用案例是在 C 語言中進行子類別化。如果你的程式碼依賴
sizeof(PyArrayObject)
為常數,則必須在匯入時新增以下檢查if (sizeof(PyArrayObject) < PyArray_Type.tp_basicsize) { PyErr_SetString(PyExc_ImportError, "Binary incompatibility with NumPy, must recompile/update X."); return NULL; }
為了確保你的程式碼不必針對特定的 NumPy 版本進行編譯,你可以新增一個常數,為 NumPy 中的變更留下空間。保證與任何未來 NumPy 版本相容的解決方案需要使用執行階段計算偏移量和配置大小。
PyArray_Type
型別物件實作了 Python 物件
的許多功能,包括 tp_as_number
、tp_as_sequence
、tp_as_mapping
和 tp_as_buffer
介面。rich comparison
(豐富比較)也與新式屬性查找一起使用,用於成員 (tp_members
) 和屬性 (tp_getset
)。PyArray_Type
也可以子型別化。
提示
tp_as_number
方法使用通用方法來呼叫已註冊用於處理操作的任何函數。當匯入 _multiarray_umath
模組時,它會將所有陣列的數值運算設定為對應的 ufunc。此選擇可以使用 PyUFunc_ReplaceLoopBySignature
更改。
PyGenericArrType_Type#
-
PyTypeObject PyGenericArrType_Type#
PyGenericArrType_Type
是 PyTypeObject 定義,它建立numpy.generic
python 型別。
PyArrayDescr_Type 和 PyArray_Descr#
-
PyTypeObject PyArrayDescr_Type#
PyArrayDescr_Type
是資料型別描述符物件的內建型別,用於描述如何解釋組成陣列的位元組。內建資料型別有 21 個靜態定義的PyArray_Descr
物件。雖然這些物件參與參考計數,但它們的參考計數永遠不應達到零。還有一個動態的使用者定義PyArray_Descr
物件表,也會被維護。一旦資料型別描述符物件被「註冊」,它也永遠不應被取消分配。函數PyArray_DescrFromType
(…) 可用於從列舉型別編號(內建或使用者定義)檢索PyArray_Descr
物件。
-
type PyArray_DescrProto#
與
PyArray_Descr
結構相同。此結構用於靜態定義原型,以便透過PyArray_RegisterDataType
註冊新的舊版 DType。詳情請參閱
PyArray_RegisterDataType
中的註解。
-
type PyArray_Descr#
PyArray_Descr
結構位於PyArrayDescr_Type
的核心。雖然這裡為了完整性而描述它,但應將其視為 NumPy 的內部結構,並透過PyArrayDescr_*
或PyDataType*
函數和巨集進行操作。此結構的大小可能會在 NumPy 版本之間變更。為了確保相容性永遠不要宣告結構的非指標實例
永遠不要執行指標運算
永遠不要使用
sizeof(PyArray_Descr)
它具有以下結構
typedef struct { PyObject_HEAD PyTypeObject *typeobj; char kind; char type; char byteorder; char _former_flags; // unused field int type_num; /* * Definitions after this one must be accessed through accessor * functions (see below) when compiling with NumPy 1.x support. */ npy_uint64 flags; npy_intp elsize; npy_intp alignment; NpyAuxData *c_metadata; npy_hash_t hash; void *reserved_null[2]; // unused field, must be NULLed. } PyArray_Descr;
某些 dtype 具有其他成員,可以透過 PyDataType_NAMES、PyDataType_FIELDS、PyDataType_SUBARRAY 和在某些情況下 (時間) PyDataType_C_METADATA 存取。
-
PyTypeObject *typeobj#
指向型別物件的指標,該物件是此陣列元素對應的 Python 型別。對於內建型別,這指向對應的陣列純量。對於使用者定義的型別,這應該指向使用者定義的型別物件。此型別物件可以繼承自陣列純量,也可以不繼承。如果它不繼承自陣列純量,則應在
flags
成員中設定NPY_USE_GETITEM
和NPY_USE_SETITEM
旗標。
-
char kind#
一個字元代碼,指示陣列的種類(使用陣列介面型別字串表示法)。‘b’ 代表布林值,‘i’ 代表帶符號整數,‘u’ 代表無符號整數,‘f’ 代表浮點數,‘c’ 代表複數浮點數,‘S’ 代表 8 位元以零結尾的位元組,‘U’ 代表 32 位元/字元 unicode 字串,而 ‘V’ 代表任意。
-
char type#
一個傳統的字元代碼,指示資料型別。
-
char byteorder#
一個字元,指示位元組順序:‘>’ (大端序),‘<’ (小端序),‘=’ (原生),‘|’ (不相關,忽略)。所有內建資料型別的位元組順序都是 ‘=’。
-
npy_uint64 flags#
一個資料型別位元旗標,用於判斷資料型別是否表現出類似物件陣列的行為。此成員中的每個位元都是一個旗標,其名稱為
-
int type_num#
一個唯一識別資料型別的數字。對於新的資料型別,此數字在資料型別註冊時被分配。
-
npy_intp elsize#
對於始終大小相同的資料型別(例如 long),這保存資料型別的大小。對於不同陣列可以具有不同元素大小的彈性資料型別,這應該為 0。
請參閱 PyDataType_ELSIZE 和 PyDataType_SET_ELSIZE,以了解在 NumPy 1.x 相容的方式中存取此欄位的方法。
-
npy_intp alignment#
一個數字,提供此資料型別的對齊資訊。具體來說,它顯示了編譯器將此型別的項目放置在距離 2 元素結構(其第一個元素是
char
)的開頭有多遠:offsetof(struct {char c; type v;}, v)
請參閱 PyDataType_ALIGNMENT,以了解在 NumPy 1.x 相容的方式中存取此欄位的方法。
-
NpyAuxData *c_metadata#
特定於特定 dtype 的 C 實作的元數據。為 NumPy 1.7.0 新增。
-
type npy_hash_t#
-
npy_hash_t *hash#
用於快取雜湊值。
-
NPY_ITEM_HASOBJECT#
與
NPY_ITEM_REFCOUNT
相同。
-
NPY_LIST_PICKLE#
表示此資料型別的陣列在 pickle 之前必須轉換為列表。
-
NPY_ITEM_IS_POINTER#
表示該項目是指向某些其他資料型別的指標
-
NPY_NEEDS_INIT#
表示此資料型別的記憶體在建立時必須初始化(設定為 0)。
-
NPY_NEEDS_PYAPI#
指示此資料類型在存取期間需要 Python C-API(因此,如果需要陣列存取,請勿放棄 GIL)。
-
NPY_USE_GETITEM#
在陣列存取時,使用
f->getitem
函數指標,而不是標準轉換為陣列純量。如果您沒有定義與資料類型一起使用的陣列純量,則必須使用。
-
NPY_USE_SETITEM#
當從陣列純量建立 0 維陣列時,使用
f->setitem
而不是從陣列純量的標準複製。如果您沒有定義與資料類型一起使用的陣列純量,則必須使用。
-
NPY_FROM_FIELDS#
如果這些位元在資料類型的任何欄位中設定,則為父資料類型繼承的位元。目前(
NPY_NEEDS_INIT
|NPY_LIST_PICKLE
|NPY_ITEM_REFCOUNT
|NPY_NEEDS_PYAPI
)。
-
NPY_OBJECT_DTYPE_FLAGS#
物件資料類型設定的位元:(
NPY_LIST_PICKLE
|NPY_USE_GETITEM
|NPY_ITEM_IS_POINTER
|NPY_ITEM_REFCOUNT
|NPY_NEEDS_INIT
|NPY_NEEDS_PYAPI
)。
-
int PyDataType_FLAGCHK(PyArray_Descr *dtype, int flags)#
如果為資料類型物件設定了所有給定的旗標,則傳回 true。
-
int PyDataType_REFCHK(PyArray_Descr *dtype)#
等同於
PyDataType_FLAGCHK
(dtype,NPY_ITEM_REFCOUNT
)。
PyArray_ArrFuncs#
-
PyArray_ArrFuncs *PyDataType_GetArrFuncs(PyArray_Descr *dtype)#
擷取資料類型的舊版 PyArray_ArrFuncs(不會失敗)。
New in version NumPy: 2.0 此函數在 NumPy 2.0 中以向後相容和可回溯移植的方式新增(請參閱
npy_2_compat.h
)。先前存取PyArray_Descr
的->f
插槽的任何程式碼,現在都必須使用此函數並將其回溯移植以使用 1.x 編譯。(npy_2_compat.h
標頭可以為此目的而供應。)
-
type PyArray_ArrFuncs#
實作內部功能的函數。並非所有這些函數指標都必須為給定的類型定義。必要的成員為
nonzero
、copyswap
、copyswapn
、setitem
、getitem
和cast
。這些假定為非NULL
,且NULL
項目將導致程式崩潰。其他函數可以是NULL
,這僅表示該資料類型的功能會減少。(此外,當您註冊使用者定義的資料類型時,如果 nonzero 函數為NULL
,則會以預設函數填入。)typedef struct { PyArray_VectorUnaryFunc *cast[NPY_NTYPES_LEGACY]; PyArray_GetItemFunc *getitem; PyArray_SetItemFunc *setitem; PyArray_CopySwapNFunc *copyswapn; PyArray_CopySwapFunc *copyswap; PyArray_CompareFunc *compare; PyArray_ArgFunc *argmax; PyArray_DotFunc *dotfunc; PyArray_ScanFunc *scanfunc; PyArray_FromStrFunc *fromstr; PyArray_NonzeroFunc *nonzero; PyArray_FillFunc *fill; PyArray_FillWithScalarFunc *fillwithscalar; PyArray_SortFunc *sort[NPY_NSORTS]; PyArray_ArgSortFunc *argsort[NPY_NSORTS]; PyObject *castdict; PyArray_ScalarKindFunc *scalarkind; int **cancastscalarkindto; int *cancastto; void *_unused1; void *_unused2; void *_unused3; PyArray_ArgFunc *argmin; } PyArray_ArrFuncs;
行為良好的區段的概念用於函數指標的描述中。行為良好的區段是指對於資料類型而言,對齊且為原生機器位元組順序的區段。
nonzero
、copyswap
、copyswapn
、getitem
和setitem
函數可以(且必須)處理行為不良的陣列。其他函數則需要行為良好的記憶體區段。註記
這些函數在很大程度上是舊版 API,但是,某些函數仍然在使用。從 NumPy 2.x 開始,它們僅透過 PyDataType_GetArrFuncs 提供(請參閱該函數以取得更多詳細資訊)。在使用結構中定義的任何函數之前,您應檢查它是否為
NULL
。一般來說,可以預期getitem
、setitem
、copyswap
和copyswapn
函數會被定義,但所有函數都預期會被較新的 API 取代。例如,PyArray_Pack
是setitem
的更強大版本,例如,它可以正確處理轉換。-
void cast(void *from, void *to, npy_intp n, void *fromarr, void *toarr)#
函數指標陣列,用於將目前類型轉換為所有其他內建類型。每個函數都會將 from 指向的連續、對齊且未交換的緩衝區,轉換為 to 指向的連續、對齊且未交換的緩衝區。要轉換的項目數由 n 給定,而引數 fromarr 和 toarr 會被解譯為彈性陣列的 PyArrayObject,以取得項目大小資訊。
-
PyObject *getitem(void *data, void *arr)#
指向一個函數的指標,該函數從 data 指向的陣列物件 arr 的單個元素傳回標準 Python 物件。此函數必須能夠正確處理「行為不良」(未對齊和/或已交換)的陣列。
-
int setitem(PyObject *item, void *data, void *arr)#
指向一個函數的指標,該函數將 Python 物件 item 設定到陣列 arr 中,位置由 data 指向。此函數處理「行為不良」的陣列。如果成功,則傳回零,否則,傳回負一(並設定 Python 錯誤)。
-
void copyswapn(void *dest, npy_intp dstride, void *src, npy_intp sstride, npy_intp n, int swap, void *arr)#
-
void copyswap(void *dest, void *src, int swap, void *arr)#
這些成員都是指向函數的指標,用於將資料從 src 複製到 dest,並在指示時進行 swap。arr 的值僅用於彈性(
NPY_STRING
、NPY_UNICODE
和NPY_VOID
)陣列(並從arr->descr->elsize
取得)。第二個函數複製單個值,而第一個函數使用提供的步幅循環處理 n 個值。這些函數可以處理行為不良的 src 資料。如果 src 為 NULL,則不執行任何複製。如果 swap 為 0,則不發生位元組交換。假定 dest 和 src 不重疊。如果它們重疊,則先使用memmove
(…),然後再使用具有 NULL 值的src
的copyswap(n)
。
-
int compare(const void *d1, const void *d2, void *arr)#
指向一個函數的指標,該函數比較陣列
arr
的兩個元素,分別由d1
和d2
指向。此函數需要行為良好的(對齊且未交換)陣列。如果 *d1
> *d2
,則傳回值為 1;如果 *d1
== *d2
,則傳回值為 0;如果 *d1
< *d2
,則傳回值為 -1。陣列物件arr
用於擷取彈性陣列的項目大小和欄位資訊。
-
int argmax(void *data, npy_intp n, npy_intp *max_ind, void *arr)#
指向一個函數的指標,該函數擷取
arr
中n
個元素中最大元素的索引,從data
指向的元素開始。此函數要求記憶體區段是連續且行為良好的。傳回值始終為 0。最大元素的索引會在max_ind
中傳回。
-
void dotfunc(void *ip1, npy_intp is1, void *ip2, npy_intp is2, void *op, npy_intp n, void *arr)#
指向一個函數的指標,該函數將兩個長度為
n
的序列相乘在一起,將它們相加,並將結果放在arr
的op
指向的元素中。兩個序列的開頭分別由ip1
和ip2
指向。要跳到每個序列中的下一個元素,分別需要跳躍is1
和is2
位元組。此函數需要行為良好的(但不一定連續的)記憶體。
-
int scanfunc(FILE *fd, void *ip, void *arr)#
指向一個函數的指標,該函數從檔案描述符
fd
掃描(scanf 樣式)對應類型的一個元素到ip
指向的陣列記憶體中。假定陣列是行為良好的。最後一個引數arr
是要掃描到的陣列。傳回成功指派的接收引數的數量(如果第一個接收引數指派之前發生比對失敗,則可能為零),如果第一個接收引數指派之前發生輸入失敗,則傳回 EOF。此函數應在不持有 Python GIL 的情況下呼叫,並且必須抓取它以進行錯誤報告。
-
int fromstr(char *str, void *ip, char **endptr, void *arr)#
指向一個函數的指標,該函數將
str
指向的字串轉換為對應類型的一個元素,並將其放在ip
指向的記憶體位置中。轉換完成後,*endptr
指向字串的其餘部分。最後一個引數arr
是 ip 指向的陣列(可變大小資料類型需要)。成功時傳回 0,失敗時傳回 -1。需要行為良好的陣列。此函數應在不持有 Python GIL 的情況下呼叫,並且必須抓取它以進行錯誤報告。
-
void fill(void *data, npy_intp length, void *arr)#
指向一個函數的指標,該函數使用資料填滿給定長度的連續陣列。陣列的前兩個元素必須已填入。從這兩個值,將計算出增量,並且將透過重複新增此計算出的增量來計算項目 3 到結尾的值。資料緩衝區必須行為良好。
-
void fillwithscalar(void *buffer, npy_intp length, void *value, void *arr)#
指向一個函數的指標,該函數使用單個純量
value
填滿給定length
的連續buffer
,其位址已給定。最後一個引數是陣列,需要它來取得可變長度陣列的項目大小。
-
int sort(void *start, npy_intp length, void *arr)#
指向特定排序演算法的函數指標陣列。使用金鑰取得特定的排序演算法(目前定義了
NPY_QUICKSORT
、NPY_HEAPSORT
和NPY_MERGESORT
)。這些排序會就地完成,假定資料是連續且對齊的。
-
int argsort(void *start, npy_intp *result, npy_intp length, void *arr)#
此資料類型的排序演算法的函數指標陣列。與 sort 相同的排序演算法可用。產生排序的索引會在
result
中傳回(必須使用索引 0 到length-1
(含)初始化)。
-
NPY_SCALARKIND scalarkind(PyArrayObject *arr)#
一個函數,用於決定應如何解譯此類型的純量。引數為
NULL
或包含資料的 0 維陣列(如果需要該陣列來決定純量的種類)。傳回值必須為NPY_SCALARKIND
類型。
-
int **cancastscalarkindto#
可以是
NULL
或NPY_NSCALARKINDS
指標的陣列。這些指標應為NULL
或整數陣列的指標(以NPY_NOTYPE
終止),指示指定種類的此資料類型的純量可以安全轉換為的資料類型(這通常表示不會遺失精確度)。
-
int *cancastto#
可以是
NULL
或整數陣列(以NPY_NOTYPE
終止),指示此資料類型可以安全轉換為的資料類型(這通常表示不會遺失精確度)。
-
void cast(void *from, void *to, npy_intp n, void *fromarr, void *toarr)#
PyArrayMethod_Context 和 PyArrayMethod_Spec#
-
type PyArrayMethodObject_tag#
用於表示 ArrayMethod 迴圈中方法「self」的不透明結構。
-
type PyArrayMethod_Context#
一個結構,傳遞到 ArrayMethod 迴圈中,以提供迴圈執行階段使用的上下文。
typedef struct { PyObject *caller; struct PyArrayMethodObject_tag *method; PyArray_Descr *const *descriptors; } PyArrayMethod_Context
-
struct PyArrayMethodObject_tag *method#
方法「self」。目前,此物件是不透明指標。
-
PyArray_Descr **descriptors#
用於 ufunc 迴圈的描述器陣列,由
resolve_descriptors
填入。陣列的長度為nin
+nout
。
-
struct PyArrayMethodObject_tag *method#
-
type PyArrayMethod_Spec#
用於向 NumPy 註冊 ArrayMethod 的結構。我們使用 Python 有限 API 使用的槽機制。有關槽定義,請參見下文。
typedef struct { const char *name; int nin, nout; NPY_CASTING casting; NPY_ARRAYMETHOD_FLAGS flags; PyArray_DTypeMeta **dtypes; PyType_Slot *slots; } PyArrayMethod_Spec;
-
const char *name#
迴圈的名稱。
-
int nin#
輸入運算元的數量
-
int nout#
輸出運算元的數量。
-
NPY_CASTING casting#
用於指示轉型操作應具有的最小允許程度。例如,如果轉型操作在某些情況下可能是安全的,但在其他情況下可能是不安全的,則應設定
NPY_UNSAFE_CASTING
。不適用於 ufunc 迴圈,但仍必須設定。
-
NPY_ARRAYMETHOD_FLAGS flags#
為方法設定的旗標。
-
PyArray_DTypeMeta **dtypes#
迴圈的 DType。長度必須為
nin
+nout
。
-
PyType_Slot *slots#
方法的槽陣列。槽 ID 必須是以下值之一。
-
const char *name#
PyArray_DTypeMeta 和 PyArrayDTypeMeta_Spec#
-
PyTypeObject PyArrayDTypeMeta_Type#
對應於
PyArray_DTypeMeta
的 python 型別物件。
-
type PyArray_DTypeMeta#
主要是不透明的結構,代表 DType 類別。每個實例都為單個 NumPy 資料型別定義一個元類別。資料型別可以是無參數或參數化的。對於無參數型別,DType 類別與從 DType 類別建立的描述器實例具有一對一的對應關係。參數化型別可以對應於許多不同的 dtype 實例,具體取決於所選的參數。此型別可在公開的
numpy/dtype_api.h
標頭中取得。目前,有限 CPython API 不支援使用此結構,因此如果設定了Py_LIMITED_API
,則此型別是PyTypeObject
的 typedef。typedef struct { PyHeapTypeObject super; PyArray_Descr *singleton; int type_num; PyTypeObject *scalar_type; npy_uint64 flags; void *dt_slots; void *reserved[3]; } PyArray_DTypeMeta
-
PyHeapTypeObject super#
超類別,提供 Python 物件 API 的掛鉤。設定此結構的成員以填入實作
PyTypeObject
API 的函式(例如tp_new
)。
-
PyArray_Descr *singleton#
適用於用作資料型別的單例描述器的描述器實例。這對於非參數型別非常有用,這些型別代表簡單的舊式資料型別,其中所有型別的資料只有一個邏輯描述器實例。如果單例實例不適用,則可以為 NULL。
-
int type_num#
對應於舊版資料型別的型別編號。在 NumPy 外部定義的資料型別以及可能隨 NumPy 提供的未來資料型別將
type_num
設定為 -1,因此不應依賴此值來區分資料型別。
-
PyTypeObject *scalar_type#
此資料型別的純量實例的型別。
-
npy_uint64 flags#
可以設定旗標以向 NumPy 指示此資料型別具有選用行為。有關允許的旗標值列表,請參見旗標。
-
void *dt_slots#
指向私有結構的不透明指標,其中包含 DType API 中函式的實作。這是從用於初始化 DType 的
PyArrayDTypeMeta_Spec
實例的slots
成員填入的。
-
PyHeapTypeObject super#
-
type PyArrayDTypeMeta_Spec#
用於使用
PyArrayInitDTypeMeta_FromSpec
函式初始化新 DType 的結構。typedef struct { PyTypeObject *typeobj; int flags; PyArrayMethod_Spec **casts; PyType_Slot *slots; PyTypeObject *baseclass; }
-
PyTypeObject *typeobj#
NULL
或與 DType 關聯的 python 純量的型別。對陣列進行純量索引會傳回具有此型別的項目。
-
int flags#
DType 類別的靜態旗標,指示 DType 是否為參數化、抽象或表示數值資料。後者是選用的,但設定它以向下游程式碼指示 DType 是否表示數字資料(整數、浮點數或其他數值資料型別)或其他內容(例如字串、單位或日期)很有用。
-
PyArrayMethod_Spec **casts;#
DType 定義的轉型的 ArrayMethod 規格的
NULL
終止陣列。
-
PyType_Slot *slots;#
DType API 中函式實作的槽規格的
NULL
終止陣列。槽 ID 必須是 槽 ID 和 API 函式類型定義 中列舉的 DType 槽 ID 之一。
-
PyTypeObject *typeobj#
公開的 DTypes 類別 (PyArray_DTypeMeta
物件)#
為了與促銷器搭配使用,NumPy 公開了許多遵循 PyArray_<Name>DType
模式的 Dtype,這些 Dtype 對應於 np.dtypes 中找到的那些。
此外,三個 DType PyArray_PyLongDType
、PyArray_PyFloatDType
、PyArray_PyComplexDType
對應於 Python 純量值。這些不能在所有位置使用,但確實允許常見的 dtype 操作,並且使用它們實作促銷可能是必要的。
此外,還定義了以下抽象 DType,它們涵蓋內建 NumPy DType 和 python DType,並且使用者原則上可以從它們繼承子類別(這不會繼承任何 DType 特定功能):* PyArray_IntAbstractDType
* PyArray_FloatAbstractDType
* PyArray_ComplexAbstractDType
警告
從 NumPy 2.0 開始,這些 DType 的 *唯一* 有效用途是方便地註冊促銷器,例如比對「任何整數」(和子類別檢查)。因此,它們不會公開給 Python。
PyUFunc_Type 和 PyUFuncObject#
-
PyTypeObject PyUFunc_Type#
ufunc 物件是透過建立
PyUFunc_Type
來實作的。它是一個非常簡單的型別,僅實作基本 getattribute 行為、列印行為,並且具有呼叫行為,允許這些物件充當函式。ufunc 背後的基本概念是為每個支援運算的資料型別保留對快速一維(向量)迴圈的參考。這些一維迴圈都具有相同的簽章,並且是建立新 ufunc 的關鍵。它們由通用迴圈程式碼適當地呼叫,以實作 N 維函式。還為浮點和複數浮點陣列定義了一些通用一維迴圈,允許您使用單個純量函式(例如 atanh)定義 ufunc。
-
type PyUFuncObject#
ufunc 的核心是
PyUFuncObject
,它包含呼叫執行實際工作的底層 C 程式碼迴圈所需的所有資訊。雖然此處為了完整性而對其進行了描述,但應將其視為 NumPy 的內部元件,並透過PyUFunc_*
函式進行操作。此結構的大小可能會因 NumPy 版本而異。為確保相容性永遠不要宣告結構的非指標實例
永遠不要執行指標運算
切勿使用
sizeof(PyUFuncObject)
它具有以下結構
typedef struct { PyObject_HEAD int nin; int nout; int nargs; int identity; PyUFuncGenericFunction *functions; void **data; int ntypes; int reserved1; const char *name; char *types; const char *doc; void *ptr; PyObject *obj; PyObject *userloops; int core_enabled; int core_num_dim_ix; int *core_num_dims; int *core_dim_ixs; int *core_offsets; char *core_signature; PyUFunc_TypeResolutionFunc *type_resolver; void *reserved2; void *reserved3; npy_uint32 *op_flags; npy_uint32 *iter_flags; /* new in API version 0x0000000D */ npy_intp *core_dim_sizes; npy_uint32 *core_dim_flags; PyObject *identity_value; /* Further private slots (size depends on the NumPy version) */ } PyUFuncObject;
-
int nin#
輸入引數的數量。
-
int nout#
輸出引數的數量。
-
int nargs#
引數總數 (nin + nout)。此值必須小於
NPY_MAXARGS
。
-
int identity#
PyUFunc_One
、PyUFunc_Zero
、PyUFunc_MinusOne
、PyUFunc_None
、PyUFunc_ReorderableNone
或PyUFunc_IdentityValue
之一,以指示此運算的單位元素。它僅用於對空陣列進行類似 reduce 的呼叫。
-
void functions(char **args, npy_intp *dims, npy_intp *steps, void *extradata)#
函式指標陣列 — ufunc 支援的每種資料型別各有一個。這是向量迴圈,呼叫它以實作底層函式 dims [0] 次。第一個引數 args 是 nargs 個指向行為正常的記憶體的指標陣列。輸入引數的資料指標在前,後跟輸出引數的資料指標。必須跳過多少位元組才能到達序列中的下一個元素由 steps 陣列中的對應條目指定。最後一個引數允許迴圈接收額外資訊。這通常用於使單個通用向量迴圈可以用於多個函式。在這種情況下,要呼叫的實際純量函式作為 extradata 傳遞。此函式指標陣列的大小為 ntypes。
-
void **data#
要傳遞給一維向量迴圈的額外資料,如果不需要額外資料,則為
NULL
。此 C 陣列的大小 (即 ntypes) 必須與函式陣列的大小相同。如果不需要 extra_data,則使用NULL
。UFunc 的多個 C-API 呼叫只是一維向量迴圈,它們利用此額外資料來接收指向要呼叫的實際函式的指標。
-
int ntypes#
ufunc 支援的資料型別數量。此數字指定有多少不同的 1 維迴圈(內建資料型別的)可用。
-
char *name#
ufunc 的字串名稱。這用於動態建構 ufunc 的 __doc__ 屬性。
-
char *types#
\(nargs \times ntypes\) 8 位元 type_numbers 的陣列,其中包含每個受支援(內建)資料型別的函式型別簽章。對於 ntypes 個函式中的每一個,此陣列中的對應型別編號集顯示應如何在 1 維向量迴圈中解譯 args 引數。這些型別編號不必是相同的型別,並且支援混合型別 ufunc。
-
char *doc#
ufunc 的文件。不應包含函式簽章,因為這會在檢索 __doc__ 時動態產生。
-
void *ptr#
任何動態分配的記憶體。目前,這用於從 python 函式建立的動態 ufunc,以儲存型別、資料和名稱成員的空間。
-
PyObject *userloops#
使用者定義型別的使用者定義 1 維向量迴圈字典(儲存為 CObject ptr)。使用者可以為任何使用者定義型別註冊迴圈。它由型別編號檢索。使用者定義的型別編號始終大於
NPY_USERDEF
。
-
int core_enabled#
0 代表純量 ufunc;1 代表廣義 ufunc
-
int core_num_dim_ix#
簽章中不同核心維度名稱的數量
-
int *core_num_dims#
每個引數的核心維度數量
-
int *core_dim_ixs#
以扁平形式表示的維度索引;引數
k
的索引儲存在core_dim_ixs[core_offsets[k] : core_offsets[k] + core_numdims[k]]
中
-
int *core_offsets#
每個引數在
core_dim_ixs
中的第一個核心維度的位置,相當於 cumsum(core_num_dims
)
-
char *core_signature#
核心簽章字串
-
PyUFunc_TypeResolutionFunc *type_resolver#
一個函式,用於解析型別並使用輸入和輸出的 dtype 填入陣列
-
type PyUFunc_TypeResolutionFunc#
type_resolver
的函式指標型別
-
type PyUFunc_TypeResolutionFunc#
-
npy_uint32 op_flags#
覆寫每個 ufunc 運算元的預設運算元旗標。
-
npy_uint32 iter_flags#
覆寫 ufunc 的預設 nditer 旗標。
在 API 版本 0x0000000D 中新增
-
npy_intp *core_dim_sizes#
對於每個不同的核心維度,如果
UFUNC_CORE_DIM_SIZE_INFERRED
為0
,則可能的凍結大小
-
npy_uint32 *core_dim_flags#
對於每個不同的核心維度,一組旗標(
UFUNC_CORE_DIM_CAN_IGNORE
和UFUNC_CORE_DIM_SIZE_INFERRED
)
-
PyObject *identity_value#
縮減的單位元素,當
PyUFuncObject.identity
等於PyUFunc_IdentityValue
時。
-
UFUNC_CORE_DIM_CAN_IGNORE#
如果維度名稱以
?
結尾
PyArrayIter_Type 和 PyArrayIterObject#
-
PyTypeObject PyArrayIter_Type#
這是一個迭代器物件,可輕鬆迴圈 N 維陣列。它是從 ndarray 的 flat 屬性傳回的物件。它也廣泛用於整個實作內部,以迴圈 N 維陣列。tp_as_mapping 介面已實作,以便可以對迭代器物件建立索引(使用一維索引),並且透過 tp_methods 表格實作了一些方法。此物件實作了 next 方法,並且可以在 Python 中可以使用迭代器的任何位置使用。
-
type PyArrayIterObject#
對應於
PyArrayIter_Type
物件的 C 結構是PyArrayIterObject
。PyArrayIterObject
用於追蹤指向 N 維陣列的指標。它包含用於快速遍歷陣列的關聯資訊。可以透過三種基本方式調整指標:1) 以 C 風格的連續方式前進到陣列中的「下一個」位置,2) 前進到陣列中的任意 N 維座標,以及 3) 前進到陣列中的任意一維索引。PyArrayIterObject
結構的成員用於這些計算中。迭代器物件保留其自身的維度和步幅資訊,這些資訊關於陣列。可以根據需要調整此資訊以進行「廣播」,或僅在特定維度上迴圈。typedef struct { PyObject_HEAD int nd_m1; npy_intp index; npy_intp size; npy_intp coordinates[NPY_MAXDIMS_LEGACY_ITERS]; npy_intp dims_m1[NPY_MAXDIMS_LEGACY_ITERS]; npy_intp strides[NPY_MAXDIMS_LEGACY_ITERS]; npy_intp backstrides[NPY_MAXDIMS_LEGACY_ITERS]; npy_intp factors[NPY_MAXDIMS_LEGACY_ITERS]; PyArrayObject *ao; char *dataptr; npy_bool contiguous; } PyArrayIterObject;
-
int nd_m1#
\(N-1\),其中 \(N\) 是底層陣列中的維度數。
-
npy_intp *backstrides#
從維度的末尾跳回其開頭需要多少位元組。 請注意,
backstrides[k] == strides[k] * dims_m1[k]
,但此處儲存為一種最佳化。
-
PyArrayObject *ao#
指向此迭代器建立以表示的底層 ndarray 的指標。
-
char *dataptr#
此成員指向索引所指示的 ndarray 中的一個元素。
-
npy_bool contiguous#
如果底層陣列為
NPY_ARRAY_C_CONTIGUOUS
,則此旗標為 true。 它用於在可能的情況下簡化計算。
-
int nd_m1#
如何在 C 語言層級使用陣列迭代器將在後面的章節中更完整地說明。 通常,您不需要關心迭代器物件的內部結構,只需透過使用巨集 PyArray_ITER_NEXT
(it)、PyArray_ITER_GOTO
(it, dest) 或 PyArray_ITER_GOTO1D
(it, index) 與其互動即可。 所有這些巨集都要求引數 it 為 PyArrayIterObject*。
PyArrayMultiIter_Type 和 PyArrayMultiIterObject#
-
PyTypeObject PyArrayMultiIter_Type#
此類型提供一個迭代器,封裝了廣播的概念。 它允許將 \(N\) 個陣列一起廣播,以便迴圈以 C 語言風格的連續方式在廣播陣列上進行。 對應的 C 結構是
PyArrayMultiIterObject
,其記憶體佈局必須開始傳遞至PyArray_Broadcast
(obj) 函數的任何物件 obj。 廣播的執行方式是調整陣列迭代器,使每個迭代器都表示廣播的形狀和大小,但調整其 strides,以便在每次迭代中使用陣列中的正確元素。
-
type PyArrayMultiIterObject#
typedef struct { PyObject_HEAD int numiter; npy_intp size; npy_intp index; int nd; npy_intp dimensions[NPY_MAXDIMS_LEGACY_ITERS]; PyArrayIterObject *iters[]; } PyArrayMultiIterObject;
-
int numiter#
需要廣播到相同形狀的陣列數量。
-
int nd#
廣播結果中的維度數量。
-
PyArrayIterObject **iters#
迭代器物件的陣列,用於保存要一起廣播的陣列的迭代器。 返回時,迭代器會針對廣播進行調整。
-
int numiter#
PyArrayNeighborhoodIter_Type 和 PyArrayNeighborhoodIterObject#
-
PyTypeObject PyArrayNeighborhoodIter_Type#
這是一個迭代器物件,可讓您輕鬆地在 N 維鄰域上進行迴圈。
-
type PyArrayNeighborhoodIterObject#
對應於
PyArrayNeighborhoodIter_Type
物件的 C 結構是PyArrayNeighborhoodIterObject
。typedef struct { PyObject_HEAD int nd_m1; npy_intp index, size; npy_intp coordinates[NPY_MAXDIMS_LEGACY_ITERS] npy_intp dims_m1[NPY_MAXDIMS_LEGACY_ITERS]; npy_intp strides[NPY_MAXDIMS_LEGACY_ITERS]; npy_intp backstrides[NPY_MAXDIMS_LEGACY_ITERS]; npy_intp factors[NPY_MAXDIMS_LEGACY_ITERS]; PyArrayObject *ao; char *dataptr; npy_bool contiguous; npy_intp bounds[NPY_MAXDIMS_LEGACY_ITERS][2]; npy_intp limits[NPY_MAXDIMS_LEGACY_ITERS][2]; npy_intp limits_sizes[NPY_MAXDIMS_LEGACY_ITERS]; npy_iter_get_dataptr_t translate; npy_intp nd; npy_intp dimensions[NPY_MAXDIMS_LEGACY_ITERS]; PyArrayIterObject* _internal_iter; char* constant; int mode; } PyArrayNeighborhoodIterObject;
純量陣列類型#
陣列中可能存在的每個不同內建資料類型都有一個 Python 類型。 這些類型大多數是 C 語言中對應資料類型的簡單包裝器。 這些類型的 C 名稱是 Py{TYPE}ArrType_Type
,其中 {TYPE}
可以是
Bool、Byte、Short、Int、Long、LongLong、UByte、UShort、UInt、ULong、ULongLong、Half、Float、Double、LongDouble、CFloat、CDouble、CLongDouble、String、Unicode、Void、Datetime、Timedelta 和 Object。
這些類型名稱是 C-API 的一部分,因此可以在擴充 C 程式碼中建立。 還有 PyIntpArrType_Type
和 PyUIntpArrType_Type
,它們是可以容納平台上指標的其中一種整數類型的簡單替代品。 這些純量物件的結構不會公開給 C 程式碼。 函數 PyArray_ScalarAsCtype
(..) 可用於從陣列純量中提取 C 類型值,而函數 PyArray_Scalar
(…) 可用於從 C 值建構陣列純量。
其他 C 結構#
在 NumPy 的開發中,發現一些新的 C 結構很有用。 這些 C 結構至少在一個 C-API 呼叫中使用,因此在此處記錄。 定義這些結構的主要原因是為了方便使用 Python ParseTuple C-API 從 Python 物件轉換為有用的 C 物件。
PyArray_Dims#
PyArray_Chunk#
-
type PyArray_Chunk#
這等同於 Python 中的 buffer 物件結構,直到 ptr 成員。 在 32 位元平台上(即,如果
NPY_SIZEOF_INT
==NPY_SIZEOF_INTP
),len 成員也符合 buffer 物件的等效成員。 它可用於表示通用的單段記憶體區塊。typedef struct { PyObject_HEAD PyObject *base; void *ptr; npy_intp len; int flags; } PyArray_Chunk;
成員為
-
void *ptr#
指向單段記憶體區塊開頭的指標。
-
int flags#
應該用於解譯記憶體的任何資料旗標(例如
NPY_ARRAY_WRITEABLE
)。
-
void *ptr#
PyArrayInterface#
另請參閱
-
type PyArrayInterface#
定義
PyArrayInterface
結構是為了讓 NumPy 和其他擴充模組可以使用快速陣列介面協定。 支援快速陣列介面協定的物件的__array_struct__
方法應傳回PyCapsule
,其中包含指向PyArrayInterface
結構的指標,其中包含陣列的相關詳細資訊。 建立新陣列後,屬性應為DECREF
,這將釋放PyArrayInterface
結構。 請記住INCREF
物件(已檢索其__array_struct__
屬性),並將新PyArrayObject
的 base 成員指向同一個物件。 這樣,陣列的記憶體將得到正確的管理。typedef struct { int two; int nd; char typekind; int itemsize; int flags; npy_intp *shape; npy_intp *strides; void *data; PyObject *descr; } PyArrayInterface;
-
int two#
整數 2 作為健全性檢查。
-
int nd#
陣列中的維度數量。
-
char typekind#
根據 typestring 慣例,指示存在的陣列類型的字元,其中 't' -> bitfield、'b' -> Boolean、'i' -> signed integer、'u' -> unsigned integer、'f' -> floating point、'c' -> complex floating point、'O' -> object、'S' -> (byte-)string、'U' -> unicode、'V' -> void。
-
int itemsize#
陣列中每個項目所需的位元組數。
-
int flags#
NPY_ARRAY_C_CONTIGUOUS
(1)、NPY_ARRAY_F_CONTIGUOUS
(2)、NPY_ARRAY_ALIGNED
(0x100)、NPY_ARRAY_NOTSWAPPED
(0x200) 或NPY_ARRAY_WRITEABLE
(0x400) 的任何位元,用於指示有關資料的某些資訊。NPY_ARRAY_ALIGNED
、NPY_ARRAY_C_CONTIGUOUS
和NPY_ARRAY_F_CONTIGUOUS
旗標實際上可以從其他參數確定。 也可以設定旗標NPY_ARR_HAS_DESCR
(0x800),以向使用版本 3 陣列介面的物件指示結構的 descr 成員存在(使用版本 2 陣列介面的物件將忽略它)。
-
void *data#
指向陣列第一個元素的指標。
-
PyObject *descr#
一個 Python 物件,更詳細地描述資料類型(與
__array_interface__
中的 descr 鍵相同)。 如果 typekind 和 itemsize 提供足夠的資訊,則可以為NULL
。 除非 flags 中NPY_ARR_HAS_DESCR
旗標處於開啟狀態,否則也會忽略此欄位。
-
int two#
內部使用的結構#
在內部,程式碼使用一些額外的 Python 物件,主要用於記憶體管理。 這些類型無法直接從 Python 存取,也不會公開給 C-API。 在此處包含它們僅是為了完整性以及協助理解程式碼。
-
type PyUFunc_Loop1d#
C 結構的簡單連結列表,其中包含為 ufunc 的 1 維迴圈定義使用者定義資料類型的每個已定義簽章所需之資訊。
-
PyTypeObject PyArrayMapIter_Type#
進階索引是使用此 Python 類型處理的。 它只是 C 結構的鬆散包裝器,其中包含進階陣列索引所需的變數。
-
type PyArrayMapIterObject#
與
PyArrayMapIter_Type
相關聯的 C 結構。 如果您嘗試理解進階索引對應程式碼,此結構非常有用。 它在arrayobject.h
標頭中定義。 此類型未公開給 Python,並且可以用 C 結構取代。 作為 Python 類型,它利用了參考計數的記憶體管理。
NumPy C-API 和 C complex#
當您使用 NumPy C-API 時,您將可以存取複數實數宣告 npy_cdouble
和 npy_cfloat
,它們是根據 complex.h
中的 C 標準類型宣告的。 不幸的是,complex.h
包含 #define I …`(其中實際定義取決於編譯器),這表示任何執行 #include <numpy/arrayobject.h>
的下游使用者都可能定義 I
,並且在其程式碼中使用宣告 double I;
之類的東西將導致模糊的編譯器錯誤,例如
可以透過新增以下內容來避免此錯誤
#undef I
到您的程式碼中。
在 2.0 版本中變更:包含 complex.h
是 NumPy 2 中的新功能,因此定義不同 I
的程式碼可能不需要在舊版本上使用 #undef I
。 NumPy 2.0.1 簡要地包含了 #under I