ufunc API#

常數#

UFUNC_{THING}_{ERR}
UFUNC_FPE_DIVIDEBYZERO#
UFUNC_FPE_OVERFLOW#
UFUNC_FPE_UNDERFLOW#
UFUNC_FPE_INVALID#
PyUFunc_{VALUE}
PyUFunc_One#
PyUFunc_Zero#
PyUFunc_MinusOne#
PyUFunc_ReorderableNone#
PyUFunc_None#
PyUFunc_IdentityValue#

巨集#

NPY_LOOP_BEGIN_THREADS#

在通用函數程式碼中使用,僅在 loop->obj 不為 true 時 (,這不是 OBJECT 陣列迴圈) 才釋放 Python GIL。需要使用變數宣告區域中的 NPY_BEGIN_THREADS_DEF

NPY_LOOP_END_THREADS#

在通用函數程式碼中使用,以在 Python GIL 被釋放時 (因為 loop->obj 不為 true) 重新取得它。

型別#

type PyUFuncGenericFunction#

指向實際實作底層 (逐元素) 函數 \(N\) 次的函數指標,具有以下簽名

void loopfunc(char **args, npy_intp const *dimensions, npy_intp const *steps, void *data)#
參數:
  • args – 指向輸入和輸出陣列實際資料的指標陣列。輸入引數在前,輸出引數在後。

  • dimensions – 指向此函數正在迴圈處理的維度大小的指標。

  • steps – 指向位元組數的指標,該位元組數會跳到此維度中每個輸入和輸出引數的下一個元素。

  • data

    可以與 ufunc 一起儲存的任意資料 (額外引數、函數名稱,等等),並在呼叫時傳入。可能為 NULL

    在 1.23.0 版本中變更:除了 NULL 值陣列外,也接受 NULL data

這是一個專門用於雙精度浮點數加法並傳回雙精度浮點數的 func 範例。

static void
double_add(char **args,
           npy_intp const *dimensions,
           npy_intp const *steps,
           void *extra)
{
    npy_intp i;
    npy_intp is1 = steps[0], is2 = steps[1];
    npy_intp os = steps[2], n = dimensions[0];
    char *i1 = args[0], *i2 = args[1], *op = args[2];
    for (i = 0; i < n; i++) {
        *((double *)op) = *((double *)i1) +
                          *((double *)i2);
        i1 += is1;
        i2 += is2;
        op += os;
     }
}

函數#

PyObject *PyUFunc_FromFuncAndData(PyUFuncGenericFunction *func, void *const *data, const char *types, int ntypes, int nin, int nout, int identity, const char *name, const char *doc, int unused)#

從必要變數建立新的廣播通用函數。每個 ufunc 都圍繞著逐元素運算的概念而建構。每個 ufunc 物件都包含指向 1-d 迴圈的指標,這些迴圈實作每個支援型別的基本功能。

注意

funcdatatypesnamedoc 引數不會被 PyUFunc_FromFuncAndData 複製。呼叫者必須確保只要 ufunc 物件存在,這些陣列使用的記憶體就不會被釋放。

參數:
  • func – 必須指向包含 ntypesPyUFuncGenericFunction 元素的陣列。

  • data – 應為 NULL 或指向大小為 ntypes 的陣列的指標。此陣列可能包含任意額外資料,這些資料將傳遞給 func 陣列中對應的迴圈函數,包括 NULL

  • types

    長度為 (nin + nout) * ntypeschar 陣列,編碼 numpy.dtype.num (僅限內建),func 陣列中對應的函數接受此編碼。例如,對於具有三個 ntypes、兩個 nin 和一個 nout 的比較 ufunc,其中第一個函數接受 numpy.int32,第二個函數接受 numpy.int64,兩者都傳回 numpy.bool_,則 types 將為 (char[]) {5, 5, 0, 7, 7, 0},因為 NPY_INT32 為 5,NPY_INT64 為 7,而 NPY_BOOL 為 0。

    如果需要,也可以使用位元寬度名稱 (例如 NPY_INT32NPY_COMPLEX128 )。

    型別轉換規則 將在執行階段用於尋找輸入/輸出提供的第一個可呼叫 func

  • ntypes – ufunc 已實作多少個不同的資料型別特定函數。

  • nin – 此運算的輸入數量。

  • nout – 輸出數量

  • identityPyUFunc_OnePyUFunc_ZeroPyUFunc_MinusOnePyUFunc_None 其中之一。這指定當空陣列傳遞至 ufunc 的 reduce 方法時應傳回的內容。特殊值 PyUFunc_IdentityValue 只能與 PyUFunc_FromFuncAndDataAndSignatureAndIdentity 方法一起使用,以允許任意 Python 物件用作 identity。

  • name – ufunc 的名稱,作為 NULL 終止字串。指定名稱為 ‘add’ 或 ‘multiply’ 會啟用整數型別縮減的特殊行為,當未給定 dtype 時。如果輸入型別是小於 numpy.int_ 資料型別大小的整數 (或布林) 資料型別,則會在內部向上轉換為 numpy.int_ (或 numpy.uint) 資料型別。

  • doc – 允許傳入文件字串以與 ufunc 一起儲存。文件字串不應包含函數名稱或呼叫簽名,因為這將從物件動態判斷,並在存取 ufunc 的 __doc__ 屬性時可用。

  • unused – 未使用,且為了 C-API 的向後相容性而存在。

PyObject *PyUFunc_FromFuncAndDataAndSignature(PyUFuncGenericFunction *func, void *const *data, const char *types, int ntypes, int nin, int nout, int identity, const char *name, const char *doc, int unused, const char *signature)#

此函數與上面的 PyUFunc_FromFuncAndData 非常相似,但有一個額外的 signature 引數,用於定義 廣義通用函數。與 ufunc 如何圍繞逐元素運算建構類似,gufunc 圍繞著逐子陣列運算,signature 定義要運算的子陣列。

參數:
  • signature – 新 gufunc 的簽名。將其設定為 NULL 等同於呼叫 PyUFunc_FromFuncAndData。會複製字串,因此可以釋放傳入的緩衝區。

PyObject *PyUFunc_FromFuncAndDataAndSignatureAndIdentity(PyUFuncGenericFunction *func, void **data, char *types, int ntypes, int nin, int nout, int identity, char *name, char *doc, int unused, char *signature, PyObject *identity_value)#

此函數與上面的 PyUFunc_FromFuncAndDataAndSignature 非常相似,但有一個額外的 identity_value 引數,用於在 identity 作為 PyUFunc_IdentityValue 傳遞時,為 ufunc 定義任意 identity。

參數:
  • identity_value – 新 gufunc 的 identity。除非 identity 引數為 PyUFunc_IdentityValue,否則必須作為 NULL 傳遞。將其設定為 NULL 等同於呼叫 PyUFunc_FromFuncAndDataAndSignature。

int PyUFunc_RegisterLoopForType(PyUFuncObject *ufunc, int usertype, PyUFuncGenericFunction function, int *arg_types, void *data)#

此函數允許使用者向已建立的 ufunc 註冊 1-d 迴圈,以便在 ufunc 與其任何輸入引數作為使用者定義的資料型別呼叫時使用。這是為了使 ufunc 能夠與內建資料型別搭配運作所必需的。資料型別必須事先向 numpy 系統註冊。迴圈作為 function 傳入。此迴圈可以採用任意資料,這些資料應作為 data 傳入。迴圈所需的資料型別作為 arg_types 傳入,arg_types 必須是指向至少與 ufunc->nargs 一樣大的記憶體的指標。

int PyUFunc_RegisterLoopForDescr(PyUFuncObject *ufunc, PyArray_Descr *userdtype, PyUFuncGenericFunction function, PyArray_Descr **arg_dtypes, void *data)#

此函數的行為與上面的 PyUFunc_RegisterLoopForType 類似,不同之處在於它允許使用者使用 PyArray_Descr 物件而不是 dtype 型別編號值來註冊 1-d 迴圈。這允許為結構化陣列資料型別和自訂資料型別而不是純量資料型別註冊 1-d 迴圈。

int PyUFunc_ReplaceLoopBySignature(PyUFuncObject *ufunc, PyUFuncGenericFunction newfunc, int *signature, PyUFuncGenericFunction *oldfunc)#

在已建立的 ufunc 中,將與給定 signature 相符的 1-d 迴圈替換為新的 1-d 迴圈 newfunc。在 oldfunc 中傳回舊的 1-d 迴圈函數。成功時傳回 0,失敗時傳回 -1。此函數僅適用於內建型別 (對於使用者定義的型別,請使用 PyUFunc_RegisterLoopForType)。簽名是一個資料型別編號陣列,指示 1-d 迴圈假設的輸入,後跟輸出。

void PyUFunc_clearfperr()#

清除 IEEE 錯誤旗標。

通用函數#

每個 ufunc 的核心是一組型別特定的函數,這些函數定義每個支援型別的基本功能。這些函數必須評估底層函數 \(N\geq1\) 次。可能會傳入可用於計算的額外資料。此功能允許將某些通用函數用作這些基本迴圈函數。通用函數具有將變數指向正確位置並設定函數呼叫所需的所有程式碼。通用函數假設要呼叫的實際函數作為額外資料傳入,並使用正確的值呼叫它。所有這些函數都適合直接放置在 PyUFuncObject 結構的函數成員中儲存的函數陣列中。

void PyUFunc_f_f_As_d_d(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_d_d(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_f_f(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_g_g(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_F_F_As_D_D(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_F_F(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_D_D(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_G_G(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_e_e(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_e_e_As_f_f(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_e_e_As_d_d(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#

型別特定的核心一維函式,適用於 ufunc,其中每個計算都是透過呼叫一個接受一個輸入引數並傳回一個輸出的函式來取得。此函式會傳入 func 中。字母對應到支援資料型別的 dtypechar ( e - half, f - float, d - double, g - long double, F - cfloat, D - cdouble, G - clongdouble)。引數 func 必須支援相同的簽名。_As_X_X 變體假設 ndarray 具有一種資料型別,但會轉換值以使用接受不同資料型別的底層函式。因此,PyUFunc_f_f_As_d_d 使用資料型別為 NPY_FLOAT 的 ndarray,但會呼叫一個接受 double 並傳回 double 的 C 函式。

void PyUFunc_ff_f_As_dd_d(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_ff_f(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_dd_d(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_gg_g(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_FF_F_As_DD_D(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_DD_D(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_FF_F(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_GG_G(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_ee_e(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_ee_e_As_ff_f(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_ee_e_As_dd_d(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#

型別特定的核心一維函式,適用於 ufunc,其中每個計算都是透過呼叫一個接受兩個輸入引數並傳回一個輸出的函式來取得。要呼叫的底層函式會以 func 傳入。字母對應到通用函式支援的特定資料型別的 dtypechar。引數 func 必須支援對應的簽名。_As_XX_X 變體假設 ndarray 具有一種資料型別,但會在迴圈的每次迭代中轉換值,以使用接受不同資料型別的底層函式。

void PyUFunc_O_O(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#
void PyUFunc_OO_O(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#

單輸入、單輸出,以及雙輸入、單輸出的核心一維函式,適用於 NPY_OBJECT 資料型別。這些函式處理參考計數問題,並在發生錯誤時提早傳回。要呼叫的實際函式是 func,它必須接受具有簽名 (PyObject*) (PyObject*) (適用於 PyUFunc_O_O) 或 (PyObject*)(PyObject *, PyObject *) (適用於 PyUFunc_OO_O) 的呼叫。

void PyUFunc_O_O_method(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#

此通用一維核心函式假設 func 是一個字串,表示輸入物件的方法。對於迴圈的每次迭代,Python 物件都會從陣列中擷取出來,並呼叫其 func 方法,將結果傳回輸出陣列。

void PyUFunc_OO_O_method(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#

此通用一維核心函式假設 func 是一個字串,表示輸入物件的方法,該方法接受一個引數。args 中的第一個引數是要呼叫其函式的方法,args 中的第二個引數是傳遞給函式的引數。函式的輸出會儲存在 args 的第三個條目中。

void PyUFunc_On_Om(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)#

這是 umath.frompyfunc(function, nin, nout) 建立的動態 ufunc 使用的一維核心函式。在此情況下,func 是指向 PyUFunc_PyFuncData 結構的指標,其定義為

type PyUFunc_PyFuncData#
typedef struct {
    int nin;
    int nout;
    PyObject *callable;
} PyUFunc_PyFuncData;

在迴圈的每次迭代中,nin 個輸入物件會從其物件陣列中擷取出來,並放入引數元組中,Python callable 會使用輸入引數呼叫,而 nout 個輸出會放入其物件陣列中。

匯入 API#

PY_UFUNC_UNIQUE_SYMBOL#
NO_IMPORT_UFUNC#
int PyUFunc_ImportUFuncAPI(void)#

確保 UFunc C-API 已匯入且可使用。成功時傳回 0,如果無法匯入 NumPy 且已設定錯誤,則傳回 -1。雖然最好在模組初始化時呼叫一次,但此函式即使多次呼叫也非常輕量。

版本 2.0 新增: 此函式主要檢查 PyUFunc_API == NULL,因此如果需要,可以手動向後移植。

import_ufunc(void)#

這些是從擴充模組以與陣列 C-API 相同的方式存取 ufunc C-API 的常數和函式。import_ufunc () 函式必須始終呼叫 (在擴充模組的初始化子常式中)。如果您的擴充模組在一個檔案中,則這就是所有需要的。如果您的擴充模組使用多個檔案,則其他兩個常數很有用。在這種情況下,將 PY_UFUNC_UNIQUE_SYMBOL 定義為您的程式碼獨有的內容,然後在不包含模組初始化函式但仍需要存取 UFUNC API 的原始程式檔中,將 PY_UFUNC_UNIQUE_SYMBOL 定義為先前使用的相同名稱,並同時定義 NO_IMPORT_UFUNC

C-API 實際上是一個函式指標陣列。此陣列是由 import_ufunc 建立 (並由全域變數指向)。全域變數是靜態定義的,還是允許其他檔案看到,取決於 PY_UFUNC_UNIQUE_SYMBOLNO_IMPORT_UFUNC 的狀態。