Python 型別與 C 結構#

在 C 程式碼中定義了幾個新的型別。其中大部分可以從 Python 存取,但少數由於用途有限而未公開。每個新的 Python 型別都有一個關聯的 PyObject* 具有一個內部結構,包含一個指向「方法表」的指標,該表定義了新物件在 Python 中的行為方式。當你在 C 程式碼中接收到一個 Python 物件時,你總是會得到一個指向 PyObject 結構的指標。因為 PyObject 結構非常通用,且僅定義了 PyObject_HEAD,它本身並沒有太大的意義。然而,不同的物件在 PyObject_HEAD 之後包含更多細節(但你必須轉換為正確的型別才能存取它們 — 或者使用存取器函數或巨集)。

定義的新 Python 型別#

Python 型別在 C 語言中與 Python 中的類別功能相當。透過建構一個新的 Python 型別,你可以為 Python 提供一個新的物件。ndarray 物件是在 C 語言中定義的新型別的一個例子。新型別在 C 語言中透過兩個基本步驟定義

  1. 建立一個 C 結構(通常命名為 Py{Name}Object),該結構與 PyObject 結構本身二進位相容,但包含該特定物件所需的額外資訊;

  2. 使用指向實作該型別所需行為的函數的指標來填充 PyTypeObject 表格(由 PyObject 結構的 ob_type 成員指向)。

與其使用定義 Python 類別行為的特殊方法名稱,不如使用「函數表」,它指向實作所需結果的函數。自 Python 2.2 以來,PyTypeObject 本身已變得動態,這允許 C 型別可以從 C 語言中的其他 C 型別「子型別化」,並在 Python 中子類別化。子型別繼承來自其父型別的屬性和方法。

有兩個主要的新型別:ndarray ( PyArray_Type ) 和 ufunc ( PyUFunc_Type )。其他型別扮演輔助角色:PyArrayIter_TypePyArrayMultiIter_TypePyArrayDescr_TypePyArrayIter_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_CONTIGUOUSNPY_ARRAY_F_CONTIGUOUSNPY_ARRAY_OWNDATANPY_ARRAY_ALIGNEDNPY_ARRAY_WRITEABLENPY_ARRAY_WRITEBACKIFCOPY

PyObject *weakreflist#

此成員允許陣列物件具有弱參考(使用 weakref 模組)。

註記

其他成員被視為私有且與版本相關。如果結構的大小對你的程式碼很重要,則必須特別注意。當這相關時,一個可能的使用案例是在 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_numbertp_as_sequencetp_as_mappingtp_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_NAMESPyDataType_FIELDSPyDataType_SUBARRAY 和在某些情況下 (時間) PyDataType_C_METADATA 存取。

PyTypeObject *typeobj#

指向型別物件的指標,該物件是此陣列元素對應的 Python 型別。對於內建型別,這指向對應的陣列純量。對於使用者定義的型別,這應該指向使用者定義的型別物件。此型別物件可以繼承自陣列純量,也可以不繼承。如果它不繼承自陣列純量,則應在 flags 成員中設定 NPY_USE_GETITEMNPY_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_ELSIZEPyDataType_SET_ELSIZE,以了解在 NumPy 1.x 相容的方式中存取此欄位的方法。

npy_intp alignment#

一個數字,提供此資料型別的對齊資訊。具體來說,它顯示了編譯器將此型別的項目放置在距離 2 元素結構(其第一個元素是 char)的開頭有多遠:offsetof(struct {char c; type v;}, v)

請參閱 PyDataType_ALIGNMENT,以了解在 NumPy 1.x 相容的方式中存取此欄位的方法。

PyObject *metadata#

關於此 dtype 的元數據。

NpyAuxData *c_metadata#

特定於特定 dtype 的 C 實作的元數據。為 NumPy 1.7.0 新增。

type npy_hash_t#
npy_hash_t *hash#

用於快取雜湊值。

NPY_ITEM_REFCOUNT#

表示此資料型別的項目必須進行參考計數(使用 Py_INCREFPy_DECREF)。

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#

實作內部功能的函數。並非所有這些函數指標都必須為給定的類型定義。必要的成員為 nonzerocopyswapcopyswapnsetitemgetitemcast。這些假定為非 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;

行為良好的區段的概念用於函數指標的描述中。行為良好的區段是指對於資料類型而言,對齊且為原生機器位元組順序的區段。nonzerocopyswapcopyswapngetitemsetitem 函數可以(且必須)處理行為不良的陣列。其他函數則需要行為良好的記憶體區段。

註記

這些函數在很大程度上是舊版 API,但是,某些函數仍然在使用。從 NumPy 2.x 開始,它們僅透過 PyDataType_GetArrFuncs 提供(請參閱該函數以取得更多詳細資訊)。在使用結構中定義的任何函數之前,您應檢查它是否為 NULL。一般來說,可以預期 getitemsetitemcopyswapcopyswapn 函數會被定義,但所有函數都預期會被較新的 API 取代。例如,PyArray_Packsetitem 的更強大版本,例如,它可以正確處理轉換。

void cast(void *from, void *to, npy_intp n, void *fromarr, void *toarr)#

函數指標陣列,用於將目前類型轉換為所有其他內建類型。每個函數都會將 from 指向的連續、對齊且未交換的緩衝區,轉換為 to 指向的連續、對齊且未交換的緩衝區。要轉換的項目數由 n 給定,而引數 fromarrtoarr 會被解譯為彈性陣列的 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_STRINGNPY_UNICODENPY_VOID )陣列(並從 arr->descr->elsize 取得)。第二個函數複製單個值,而第一個函數使用提供的步幅循環處理 n 個值。這些函數可以處理行為不良的 src 資料。如果 src 為 NULL,則不執行任何複製。如果 swap 為 0,則不發生位元組交換。假定 destsrc 不重疊。如果它們重疊,則先使用 memmove(…),然後再使用具有 NULL 值的 srccopyswap(n)

int compare(const void *d1, const void *d2, void *arr)#

指向一個函數的指標,該函數比較陣列 arr 的兩個元素,分別由 d1d2 指向。此函數需要行為良好的(對齊且未交換)陣列。如果 * d1 > * d2,則傳回值為 1;如果 * d1 == * d2,則傳回值為 0;如果 * d1 < * d2,則傳回值為 -1。陣列物件 arr 用於擷取彈性陣列的項目大小和欄位資訊。

int argmax(void *data, npy_intp n, npy_intp *max_ind, void *arr)#

指向一個函數的指標,該函數擷取 arrn 個元素中最大元素的索引,從 data 指向的元素開始。此函數要求記憶體區段是連續且行為良好的。傳回值始終為 0。最大元素的索引會在 max_ind 中傳回。

void dotfunc(void *ip1, npy_intp is1, void *ip2, npy_intp is2, void *op, npy_intp n, void *arr)#

指向一個函數的指標,該函數將兩個長度為 n 的序列相乘在一起,將它們相加,並將結果放在 arrop 指向的元素中。兩個序列的開頭分別由 ip1ip2 指向。要跳到每個序列中的下一個元素,分別需要跳躍 is1is2 位元組。此函數需要行為良好的(但不一定連續的)記憶體。

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 的情況下呼叫,並且必須抓取它以進行錯誤報告。

npy_bool nonzero(void *data, void *arr)#

指向一個函數的指標,如果 data 指向的 arr 項目為非零,則傳回 TRUE。此函數可以處理行為不良的陣列。

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_QUICKSORTNPY_HEAPSORTNPY_MERGESORT )。這些排序會就地完成,假定資料是連續且對齊的。

int argsort(void *start, npy_intp *result, npy_intp length, void *arr)#

此資料類型的排序演算法的函數指標陣列。與 sort 相同的排序演算法可用。產生排序的索引會在 result 中傳回(必須使用索引 0 到 length-1(含)初始化)。

PyObject *castdict#

可以是 NULL 或包含使用者定義資料類型的低階轉換函數的字典。每個函數都包裝在 PyCapsule* 中,並以資料類型編號作為索引鍵。

NPY_SCALARKIND scalarkind(PyArrayObject *arr)#

一個函數,用於決定應如何解譯此類型的純量。引數為 NULL 或包含資料的 0 維陣列(如果需要該陣列來決定純量的種類)。傳回值必須為 NPY_SCALARKIND 類型。

int **cancastscalarkindto#

可以是 NULLNPY_NSCALARKINDS 指標的陣列。這些指標應為 NULL 或整數陣列的指標(以 NPY_NOTYPE 終止),指示指定種類的此資料類型的純量可以安全轉換為的資料類型(這通常表示不會遺失精確度)。

int *cancastto#

可以是 NULL 或整數陣列(以 NPY_NOTYPE 終止),指示此資料類型可以安全轉換為的資料類型(這通常表示不會遺失精確度)。

int argmin(void *data, npy_intp n, npy_intp *min_ind, void *arr)#

指向一個函數的指標,該函數擷取 arrn 個元素中最小元素的索引,從 data 指向的元素開始。此函數要求記憶體區段是連續且行為良好的。傳回值始終為 0。最小元素的索引會在 min_ind 中傳回。

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
PyObject *caller#

呼叫者,通常是呼叫迴圈的 ufunc。當呼叫不是來自 ufunc 時(例如,轉換),可能為 NULL

struct PyArrayMethodObject_tag *method#

方法「self」。目前,此物件是不透明指標。

PyArray_Descr **descriptors#

用於 ufunc 迴圈的描述器陣列,由 resolve_descriptors 填入。陣列的長度為 nin + nout

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 必須是以下值之一。

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 成員填入的。

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 之一。

公開的 DTypes 類別 (PyArray_DTypeMeta 物件)#

為了與促銷器搭配使用,NumPy 公開了許多遵循 PyArray_<Name>DType 模式的 Dtype,這些 Dtype 對應於 np.dtypes 中找到的那些。

此外,三個 DType PyArray_PyLongDTypePyArray_PyFloatDTypePyArray_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_OnePyUFunc_ZeroPyUFunc_MinusOnePyUFunc_NonePyUFunc_ReorderableNonePyUFunc_IdentityValue 之一,以指示此運算的單位元素。它僅用於對空陣列進行類似 reduce 的呼叫。

void functions(char **args, npy_intp *dims, npy_intp *steps, void *extradata)#

函式指標陣列 — ufunc 支援的每種資料型別各有一個。這是向量迴圈,呼叫它以實作底層函式 dims [0] 次。第一個引數 argsnargs 個指向行為正常的記憶體的指標陣列。輸入引數的資料指標在前,後跟輸出引數的資料指標。必須跳過多少位元組才能到達序列中的下一個元素由 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 *obj#

對於從 python 函式動態建立的 ufunc,此成員保留對底層 Python 函式的參考。

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 的函式指標型別

npy_uint32 op_flags#

覆寫每個 ufunc 運算元的預設運算元旗標。

npy_uint32 iter_flags#

覆寫 ufunc 的預設 nditer 旗標。

在 API 版本 0x0000000D 中新增

npy_intp *core_dim_sizes#

對於每個不同的核心維度,如果 UFUNC_CORE_DIM_SIZE_INFERRED0,則可能的凍結大小

npy_uint32 *core_dim_flags#

對於每個不同的核心維度,一組旗標( UFUNC_CORE_DIM_CAN_IGNOREUFUNC_CORE_DIM_SIZE_INFERRED

PyObject *identity_value#

縮減的單位元素,當 PyUFuncObject.identity 等於 PyUFunc_IdentityValue 時。

UFUNC_CORE_DIM_CAN_IGNORE#

如果維度名稱以 ? 結尾

UFUNC_CORE_DIM_SIZE_INFERRED#

如果維度大小將從運算元而不是從凍結簽章確定

PyArrayIter_Type 和 PyArrayIterObject#

PyTypeObject PyArrayIter_Type#

這是一個迭代器物件,可輕鬆迴圈 N 維陣列。它是從 ndarray 的 flat 屬性傳回的物件。它也廣泛用於整個實作內部,以迴圈 N 維陣列。tp_as_mapping 介面已實作,以便可以對迭代器物件建立索引(使用一維索引),並且透過 tp_methods 表格實作了一些方法。此物件實作了 next 方法,並且可以在 Python 中可以使用迭代器的任何位置使用。

type PyArrayIterObject#

對應於 PyArrayIter_Type 物件的 C 結構是 PyArrayIterObjectPyArrayIterObject 用於追蹤指向 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 index#

陣列目前的 1 維索引。

npy_intp size#

底層陣列的總大小。

npy_intp *coordinates#

陣列的 \(N\) 維索引。

npy_intp *dims_m1#

陣列在每個維度的大小減 1。

npy_intp *strides#

陣列的 strides。在每個維度中跳到下一個元素需要多少位元組。

npy_intp *backstrides#

從維度的末尾跳回其開頭需要多少位元組。 請注意,backstrides[k] == strides[k] * dims_m1[k],但此處儲存為一種最佳化。

npy_intp *factors#

此陣列用於從 1 維索引計算 N 維索引。 它包含維度所需的乘積。

PyArrayObject *ao#

指向此迭代器建立以表示的底層 ndarray 的指標。

char *dataptr#

此成員指向索引所指示的 ndarray 中的一個元素。

npy_bool contiguous#

如果底層陣列為 NPY_ARRAY_C_CONTIGUOUS,則此旗標為 true。 它用於在可能的情況下簡化計算。

如何在 C 語言層級使用陣列迭代器將在後面的章節中更完整地說明。 通常,您不需要關心迭代器物件的內部結構,只需透過使用巨集 PyArray_ITER_NEXT (it)、PyArray_ITER_GOTO (it, dest) 或 PyArray_ITER_GOTO1D (it, index) 與其互動即可。 所有這些巨集都要求引數 itPyArrayIterObject*

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#

需要廣播到相同形狀的陣列數量。

npy_intp size#

廣播後的總大小。

npy_intp index#

目前(1 維)廣播結果的索引。

int nd#

廣播結果中的維度數量。

npy_intp *dimensions#

廣播結果的形狀(僅使用 nd 個插槽)。

PyArrayIterObject **iters#

迭代器物件的陣列,用於保存要一起廣播的陣列的迭代器。 返回時,迭代器會針對廣播進行調整。

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} 可以是

BoolByteShortIntLongLongLongUByteUShortUIntULongULongLongHalfFloatDoubleLongDoubleCFloatCDoubleCLongDoubleStringUnicodeVoidDatetimeTimedeltaObject

這些類型名稱是 C-API 的一部分,因此可以在擴充 C 程式碼中建立。 還有 PyIntpArrType_TypePyUIntpArrType_Type,它們是可以容納平台上指標的其中一種整數類型的簡單替代品。 這些純量物件的結構不會公開給 C 程式碼。 函數 PyArray_ScalarAsCtype (..) 可用於從陣列純量中提取 C 類型值,而函數 PyArray_Scalar (…) 可用於從 C 值建構陣列純量。

其他 C 結構#

在 NumPy 的開發中,發現一些新的 C 結構很有用。 這些 C 結構至少在一個 C-API 呼叫中使用,因此在此處記錄。 定義這些結構的主要原因是為了方便使用 Python ParseTuple C-API 從 Python 物件轉換為有用的 C 物件。

PyArray_Dims#

type PyArray_Dims#

當形狀和/或 strides 資訊應該被解譯時,此結構非常有用。 結構為

typedef struct {
    npy_intp *ptr;
    int len;
} PyArray_Dims;

此結構的成員為

npy_intp *ptr#

指向 (npy_intp) 整數列表的指標,這些整數通常表示陣列形狀或陣列 strides。

int len#

整數列表的長度。 假設可以安全地存取 ptr [0] 到 ptr [len-1]。

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;

成員為

PyObject *base#

此記憶體區塊來自的 Python 物件。 需要這樣才能正確地計算記憶體。

void *ptr#

指向單段記憶體區塊開頭的指標。

npy_intp len#

段落的長度,以位元組為單位。

int flags#

應該用於解譯記憶體的任何資料旗標(例如 NPY_ARRAY_WRITEABLE)。

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_ALIGNEDNPY_ARRAY_C_CONTIGUOUSNPY_ARRAY_F_CONTIGUOUS 旗標實際上可以從其他參數確定。 也可以設定旗標 NPY_ARR_HAS_DESCR (0x800),以向使用版本 3 陣列介面的物件指示結構的 descr 成員存在(使用版本 2 陣列介面的物件將忽略它)。

npy_intp *shape#

一個陣列,包含陣列在每個維度中的大小。

npy_intp *strides#

一個陣列,包含跳到每個維度中的下一個元素所需的位元組數。

void *data#

指向陣列第一個元素的指標。

PyObject *descr#

一個 Python 物件,更詳細地描述資料類型(與 __array_interface__ 中的 descr 鍵相同)。 如果 typekinditemsize 提供足夠的資訊,則可以為 NULL。 除非 flagsNPY_ARR_HAS_DESCR 旗標處於開啟狀態,否則也會忽略此欄位。

內部使用的結構#

在內部,程式碼使用一些額外的 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_cdoublenpy_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