NumPy 源码解析(七十九)
.\numpy\numpy\_core\src\umath\_scaled_float_dtype.c
/*
* This file implements a basic scaled float64 DType. The reason is to have
* a simple parametric DType for testing. It is not meant to be a useful
* DType by itself, but due to the scaling factor has similar properties as
* a Unit DType.
*
* The code here should be seen as a work in progress. Some choices are made
* to test certain code paths, but that does not mean that they must not
* be modified.
*
* NOTE: The tests were initially written using private API and ABI, ideally
* they should be replaced/modified with versions using public API.
*/
typedef struct {
PyArray_Descr base; /* Define structure for scaled float descriptor */
double scaling; /* Scaling factor for the float */
} PyArray_SFloatDescr;
static PyArray_DTypeMeta PyArray_SFloatDType; /* Define DTypeMeta object for scaled float */
static PyArray_SFloatDescr SFloatSingleton; /* Singleton instance of scaled float descriptor */
static int
sfloat_is_known_scalar_type(PyArray_DTypeMeta *NPY_UNUSED(cls), PyTypeObject *type)
{
/* Check if the given type is a float type */
if (type == &PyFloat_Type) {
return 1; /* Return true if it's a float */
}
return 0; /* Otherwise, return false */
}
static PyArray_Descr *
sfloat_default_descr(PyArray_DTypeMeta *NPY_UNUSED(cls))
{
Py_INCREF(&SFloatSingleton); /* Increment reference count for the singleton descriptor */
return (PyArray_Descr *)&SFloatSingleton; /* Return the descriptor as PyArray_Descr* */
}
static PyArray_Descr *
sfloat_discover_from_pyobject(PyArray_DTypeMeta *cls, PyObject *NPY_UNUSED(obj))
{
return sfloat_default_descr(cls); /* Return the default descriptor for a given Python object */
}
static PyArray_DTypeMeta *
sfloat_common_dtype(PyArray_DTypeMeta *cls, PyArray_DTypeMeta *other)
{
/* Common dtype function to check compatibility with another dtype */
if (NPY_DT_is_legacy(other) && other->type_num == NPY_DOUBLE) {
Py_INCREF(cls);
return cls; /* Return self if the other dtype is legacy and double */
}
Py_INCREF(Py_NotImplemented);
return (PyArray_DTypeMeta *)Py_NotImplemented; /* Otherwise, return NotImplemented */
}
static PyArray_Descr *
sfloat_common_instance(PyArray_Descr *descr1, PyArray_Descr *descr2)
{
PyArray_SFloatDescr *sf1 = (PyArray_SFloatDescr *)descr1;
PyArray_SFloatDescr *sf2 = (PyArray_SFloatDescr *)descr2;
/* Choose the descriptor with the larger scaling factor */
if (sf1->scaling >= sf2->scaling) {
Py_INCREF(descr1);
return descr1; /* Return the first descriptor if its scaling is larger or equal */
}
Py_INCREF(descr2);
return descr2; /* Otherwise, return the second descriptor */
}
/*
* Implement minimal getitem and setitem to make this DType mostly(?) safe to
* expose in Python.
* TODO: This should not use the old-style API, but the new-style is missing!
*/
static PyObject *
sfloat_getitem(char *data, PyArrayObject *arr)
{
PyArray_SFloatDescr *descr = (PyArray_SFloatDescr *)PyArray_DESCR(arr);
double value;
memcpy(&value, data, sizeof(double)); /* Copy the double value from data */
return PyFloat_FromDouble(value * descr->scaling); /* Return scaled float value */
}
static int
sfloat_setitem(PyObject *obj, char *data, PyArrayObject *arr)
{
# 检查对象是否为精确的浮点数类型,如果不是则抛出异常并返回-1
if (!PyFloat_CheckExact(obj)) {
PyErr_SetString(PyExc_NotImplementedError,
"Currently only accepts floats");
return -1;
}
# 获取数组对象的浮点数描述符
PyArray_SFloatDescr *descr = (PyArray_SFloatDescr *)PyArray_DESCR(arr);
# 将Python浮点数对象转换为C语言的double类型值
double value = PyFloat_AsDouble(obj);
# 将值按描述符中的缩放因子进行缩放处理
value /= descr->scaling;
# 将处理后的double值复制到数据缓冲区中
memcpy(data, &value, sizeof(double));
# 操作成功完成,返回0表示成功
return 0;
/* Special DType methods and the descr->f slot storage */
/* 定义结构体变量 sfloat_slots,包含一系列与特定数据类型相关的函数指针 */
NPY_DType_Slots sfloat_slots = {
.discover_descr_from_pyobject = &sfloat_discover_from_pyobject,
.is_known_scalar_type = &sfloat_is_known_scalar_type,
.default_descr = &sfloat_default_descr,
.common_dtype = &sfloat_common_dtype,
.common_instance = &sfloat_common_instance,
.f = {
.getitem = (PyArray_GetItemFunc *)&sfloat_getitem,
.setitem = (PyArray_SetItemFunc *)&sfloat_setitem,
}
};
/* 定义静态变量 SFloatSingleton,描述浮点数类型的属性 */
static PyArray_SFloatDescr SFloatSingleton = {{
.byteorder = '|', /* 不需要处理字节顺序 */
.flags = NPY_USE_GETITEM | NPY_USE_SETITEM,
.type_num = -1,
.elsize = sizeof(double),
.alignment = NPY_ALIGNOF(double),
},
.scaling = 1,
};
/* 复制浮点数描述符并进行缩放 */
static PyArray_Descr *sfloat_scaled_copy(PyArray_SFloatDescr *self, double factor) {
PyArray_SFloatDescr *new = PyObject_New(
PyArray_SFloatDescr, (PyTypeObject *)&PyArray_SFloatDType);
if (new == NULL) {
return NULL;
}
/* 不复制 PyObject_HEAD 部分 */
memcpy((char *)new + sizeof(PyObject),
(char *)self + sizeof(PyObject),
sizeof(PyArray_SFloatDescr) - sizeof(PyObject));
new->scaling = new->scaling * factor;
return (PyArray_Descr *)new;
}
/* Python 函数,用于复制浮点数类型并进行缩放 */
PyObject *python_sfloat_scaled_copy(PyArray_SFloatDescr *self, PyObject *arg)
{
if (!PyFloat_Check(arg)) {
PyErr_SetString(PyExc_TypeError,
"Scaling factor must be a python float.");
return NULL;
}
double factor = PyFloat_AsDouble(arg);
return (PyObject *)sfloat_scaled_copy(self, factor);
}
/* 返回浮点数类型的 scaling 属性 */
static PyObject *sfloat_get_scaling(PyArray_SFloatDescr *self, PyObject *NPY_UNUSED(args))
{
return PyFloat_FromDouble(self->scaling);
}
/* 返回浮点数类型的 __reduce__ 方法 */
static PyObject *sfloat___reduce__(PyArray_SFloatDescr *self)
{
return Py_BuildValue("(O(d))", Py_TYPE(self), self->scaling);
}
/* 定义浮点数类型的方法表 */
PyMethodDef sfloat_methods[] = {
{"scaled_by",
(PyCFunction)python_sfloat_scaled_copy, METH_O,
"Method to get a dtype copy with different scaling, mainly to "
"avoid having to implement many ways to create new instances."},
{"get_scaling",
(PyCFunction)sfloat_get_scaling, METH_NOARGS, NULL},
{"__reduce__",
(PyCFunction)sfloat___reduce__, METH_NOARGS, NULL},
{NULL, NULL, 0, NULL}
};
/* 创建新的浮点数类型对象 */
static PyObject *sfloat_new(PyTypeObject *NPY_UNUSED(cls), PyObject *args, PyObject *kwds)
{
double scaling = 1.;
static char *kwargs_strs[] = {"scaling", NULL};
if (!PyArg_ParseTupleAndKeywords(
args, kwds, "|d:_ScaledFloatTestDType", kwargs_strs, &scaling)) {
return NULL;
}
if (scaling == 1.) {
Py_INCREF(&SFloatSingleton);
return (PyObject *)&SFloatSingleton;
}
return (PyObject *)sfloat_scaled_copy(&SFloatSingleton, scaling);
}
/* 返回浮点数类型对象的字符串表示 */
static PyObject *sfloat_repr(PyArray_SFloatDescr *self)
{
PyObject *scaling = PyFloat_FromDouble(self->scaling);
/* 返回浮点数类型的字符串表示,包含 scaling 属性 */
return PyUnicode_FromFormat("<SFloatDescr with scaling %f>", self->scaling);
}
# 如果 scaling 是空指针,则返回空指针
if (scaling == NULL) {
return NULL;
}
# 使用 PyUnicode_FromFormat 函数创建一个新的 Python Unicode 对象,
# 格式化字符串为 "_ScaledFloatTestDType(scaling=%R)",其中 %R 是格式化参数,
# 表示将 scaling 对象转换为相应的 Python 表示形式
PyObject *res = PyUnicode_FromFormat(
"_ScaledFloatTestDType(scaling=%R)", scaling);
# 减少 scaling 对象的引用计数,因为在创建 res 后不再需要 scaling
Py_DECREF(scaling);
# 返回创建的 Unicode 对象 res
return res;
}
if (((PyArray_SFloatDescr *)loop_descrs[0])->scaling
== ((PyArray_SFloatDescr *)loop_descrs[1])->scaling) {
/* 检查两个描述符的 scaling 属性是否相同 */
*view_offset = 0;
// 如果相同,则视为只是一个视图,设置视图偏移为0
return NPY_NO_CASTING;
}
else if (-((PyArray_SFloatDescr *)loop_descrs[0])->scaling
== ((PyArray_SFloatDescr *)loop_descrs[1])->scaling) {
/* 检查两个描述符的 scaling 属性是否互为相反数 */
// 如果是相反数,则改变符号不会丢失精度
return NPY_EQUIV_CASTING;
}
// 如果两者不是相同的 scaling 或者互为相反数
/* 技术上讲,这不是一个安全的类型转换,因为可能会发生溢出或下溢 */
// 返回同类别的类型转换,但不保证安全性
return NPY_SAME_KIND_CASTING;
/*
* Casting to and from doubles.
*
* To keep things interesting, we ONLY define the trivial cast with a factor
* of 1. All other casts have to be handled by the sfloat to sfloat cast.
*
* The casting machinery should optimize this step away normally, since we
* flag the this is a view.
*/
static int
cast_float_to_from_sfloat(PyArrayMethod_Context *NPY_UNUSED(context),
char *const data[], npy_intp const dimensions[],
npy_intp const strides[], NpyAuxData *NPY_UNUSED(auxdata))
{
// 获取数据的长度
npy_intp N = dimensions[0];
// 输入数据指针
char *in = data[0];
// 输出数据指针
char *out = data[1];
// 遍历数据并进行类型转换
for (npy_intp i = 0; i < N; i++) {
// 将输入的 double 类型数据复制给输出
*(double *)out = *(double *)in;
// 更新输入指针的位置
in += strides[0];
// 更新输出指针的位置
out += strides[1];
}
// 返回成功状态
return 0;
}
/*
* Resolve descriptors for casting from float to sfloat and vice versa.
*/
static NPY_CASTING
float_to_from_sfloat_resolve_descriptors(
PyArrayMethodObject *NPY_UNUSED(self),
PyArray_DTypeMeta *dtypes[2],
PyArray_Descr *NPY_UNUSED(given_descrs[2]),
PyArray_Descr *loop_descrs[2],
npy_intp *view_offset)
{
// 为输入和输出的数据类型获取默认描述符
loop_descrs[0] = NPY_DT_CALL_default_descr(dtypes[0]);
if (loop_descrs[0] == NULL) {
// 如果获取失败,返回错误状态
return -1;
}
loop_descrs[1] = NPY_DT_CALL_default_descr(dtypes[1]);
if (loop_descrs[1] == NULL) {
// 如果获取失败,返回错误状态
return -1;
}
// 设置视图偏移量为0
*view_offset = 0;
// 返回无需类型转换的状态
return NPY_NO_CASTING;
}
/*
* Cast from sfloat to boolean (for testing the logical functions).
*/
static int
cast_sfloat_to_bool(PyArrayMethod_Context *NPY_UNUSED(context),
char *const data[], npy_intp const dimensions[],
npy_intp const strides[], NpyAuxData *NPY_UNUSED(auxdata))
{
// 获取数据的长度
npy_intp N = dimensions[0];
// 输入数据指针
char *in = data[0];
// 输出数据指针
char *out = data[1];
// 遍历数据并进行类型转换
for (npy_intp i = 0; i < N; i++) {
// 将输入的 double 类型数据转换为布尔类型后赋给输出
*(npy_bool *)out = *(double *)in != 0;
// 更新输入指针的位置
in += strides[0];
// 更新输出指针的位置
out += strides[1];
}
// 返回成功状态
return 0;
}
/*
* Resolve descriptors for casting from sfloat to boolean.
*/
static NPY_CASTING
sfloat_to_bool_resolve_descriptors(
PyArrayMethodObject *NPY_UNUSED(self),
PyArray_DTypeMeta *NPY_UNUSED(dtypes[2]),
PyArray_Descr *given_descrs[2],
PyArray_Descr *loop_descrs[2],
npy_intp *NPY_UNUSED(view_offset))
{
// 增加对给定描述符的引用
Py_INCREF(given_descrs[0]);
// 设置输入描述符为给定的描述符
loop_descrs[0] = given_descrs[0];
if (loop_descrs[0] == NULL) {
// 如果获取失败,返回错误状态
return -1;
}
// 设置输出描述符为布尔类型的描述符(不可能失败)
loop_descrs[1] = PyArray_DescrFromType(NPY_BOOL); /* cannot fail */
// 返回不安全类型转换状态
return NPY_UNSAFE_CASTING;
}
/*
* Initialize casting functions for sfloat.
*/
static int
sfloat_init_casts(void)
{
// 定义输入和输出的数据类型为单精度浮点型
PyArray_DTypeMeta *dtypes[2] = {&PyArray_SFloatDType, &PyArray_SFloatDType};
// 初始化类型槽
PyType_Slot slots[4] = {{0, NULL}};
// 定义方法的规范
PyArrayMethod_Spec spec = {
.name = "sfloat_to_sfloat_cast",
.nin = 1,
.nout = 1,
/* minimal guaranteed casting */
.casting = NPY_SAME_KIND_CASTING,
.flags = NPY_METH_SUPPORTS_UNALIGNED,
.dtypes = dtypes,
.slots = slots,
};
// 设置第一个槽位为解析描述符的方法
slots[0].slot = NPY_METH_resolve_descriptors;
slots[0].pfunc = &sfloat_to_sfloat_resolve_descriptors;
// 设置第二个槽位为处理步进循环的方法
slots[1].slot = NPY_METH_strided_loop;
```
# 将第一个槽位的函数指针设置为 cast_sfloat_to_sfloat_aligned 函数的地址
slots[1].pfunc = &cast_sfloat_to_sfloat_aligned;
# 设置第二个槽位的标志为 NPY_METH_unaligned_strided_loop
slots[2].slot = NPY_METH_unaligned_strided_loop;
# 将第二个槽位的函数指针设置为 cast_sfloat_to_sfloat_unaligned 函数的地址
slots[2].pfunc = &cast_sfloat_to_sfloat_unaligned;
# 向 PyArray_AddCastingImplementation_FromSpec 函数添加类型转换规范
if (PyArray_AddCastingImplementation_FromSpec(&spec, 0)) {
return -1;
}
# 设置 spec 的名称为 "float_to_sfloat_cast"
spec.name = "float_to_sfloat_cast";
# 设置 spec 的标志为 NPY_METH_NO_FLOATINGPOINT_ERRORS
spec.flags = NPY_METH_NO_FLOATINGPOINT_ERRORS;
# 获取 PyArray_DoubleDType 的指针,并将其赋值给 dtypes 数组的第一个元素
PyArray_DTypeMeta *double_DType = &PyArray_DoubleDType;
dtypes[0] = double_DType;
# 设置 slots 数组的各个槽位的值和函数指针,用于处理浮点到半浮点的转换
slots[0].slot = NPY_METH_resolve_descriptors;
slots[0].pfunc = &float_to_from_sfloat_resolve_descriptors;
slots[1].slot = NPY_METH_strided_loop;
slots[1].pfunc = &cast_float_to_from_sfloat;
slots[2].slot = 0;
slots[2].pfunc = NULL;
# 再次向 PyArray_AddCastingImplementation_FromSpec 函数添加类型转换规范
if (PyArray_AddCastingImplementation_FromSpec(&spec, 0)) {
return -1;
}
# 设置 spec 的名称为 "sfloat_to_float_cast"
spec.name = "sfloat_to_float_cast";
# 设置 dtypes 数组的第一个元素为 PyArray_SFloatDType 的指针
dtypes[0] = &PyArray_SFloatDType;
# 设置 dtypes 数组的第二个元素为 double_DType 指针
dtypes[1] = double_DType;
# 再次向 PyArray_AddCastingImplementation_FromSpec 函数添加类型转换规范
if (PyArray_AddCastingImplementation_FromSpec(&spec, 0)) {
return -1;
}
# 设置 slots 数组的各个槽位的值和函数指针,用于处理半浮点到布尔型的转换
slots[0].slot = NPY_METH_resolve_descriptors;
slots[0].pfunc = &sfloat_to_bool_resolve_descriptors;
slots[1].slot = NPY_METH_strided_loop;
slots[1].pfunc = &cast_sfloat_to_bool;
slots[2].slot = 0;
slots[2].pfunc = NULL;
# 设置 spec 的名称为 "sfloat_to_bool_cast"
spec.name = "sfloat_to_bool_cast";
# 设置 dtypes 数组的第一个元素为 PyArray_SFloatDType 的指针
dtypes[0] = &PyArray_SFloatDType;
# 设置 dtypes 数组的第二个元素为 PyArray_BoolDType 的指针
dtypes[1] = &PyArray_BoolDType;
# 再次向 PyArray_AddCastingImplementation_FromSpec 函数添加类型转换规范
if (PyArray_AddCastingImplementation_FromSpec(&spec, 0)) {
return -1;
}
# 返回 0 表示函数执行成功
return 0;
/*
* We also wish to test very simple ufunc functionality. So create two
* ufunc loops:
* 1. Multiplication, which can multiply the factors and work with that.
* 2. Addition, which needs to use the common instance, and runs into
* cast safety subtleties since we will implement it without an additional
* cast.
*/
static int
multiply_sfloats(PyArrayMethod_Context *NPY_UNUSED(context),
char *const data[], npy_intp const dimensions[],
npy_intp const strides[], NpyAuxData *NPY_UNUSED(auxdata))
{
// 获取第一个维度的大小
npy_intp N = dimensions[0];
// 获取输入数组的指针
char *in1 = data[0];
char *in2 = data[1];
// 获取输出数组的指针
char *out = data[2];
// 遍历数组进行乘法运算
for (npy_intp i = 0; i < N; i++) {
// 将输入数组中的双精度浮点数相乘,结果存入输出数组中
*(double *)out = *(double *)in1 * *(double *)in2;
// 更新输入数组和输出数组的指针位置
in1 += strides[0];
in2 += strides[1];
out += strides[2];
}
return 0;
}
static NPY_CASTING
multiply_sfloats_resolve_descriptors(
PyArrayMethodObject *NPY_UNUSED(self),
PyArray_DTypeMeta *NPY_UNUSED(dtypes[3]),
PyArray_Descr *given_descrs[3],
PyArray_Descr *loop_descrs[3],
npy_intp *NPY_UNUSED(view_offset))
{
/*
* Multiply the scaling for the result. If the result was passed in we
* simply ignore it and let the casting machinery fix it up here.
*/
// 获取第一个输入描述符的缩放因子
double factor = ((PyArray_SFloatDescr *)given_descrs[1])->scaling;
// 创建新的输出描述符,使用第一个输入描述符和缩放因子
loop_descrs[2] = sfloat_scaled_copy(
(PyArray_SFloatDescr *)given_descrs[0], factor);
// 检查是否成功创建新的输出描述符
if (loop_descrs[2] == 0) {
return -1;
}
// 增加输入描述符的引用计数
Py_INCREF(given_descrs[0]);
loop_descrs[0] = given_descrs[0];
// 增加第二个输入描述符的引用计数
Py_INCREF(given_descrs[1]);
loop_descrs[1] = given_descrs[1];
// 指定无需类型转换
return NPY_NO_CASTING;
}
/*
* Unlike the multiplication implementation above, this loops deals with
* scaling (casting) internally. This allows to test some different paths.
*/
static int
add_sfloats(PyArrayMethod_Context *context,
char *const data[], npy_intp const dimensions[],
npy_intp const strides[], NpyAuxData *NPY_UNUSED(auxdata))
{
// 获取第一个输入描述符的缩放因子
double fin1 = ((PyArray_SFloatDescr *)context->descriptors[0])->scaling;
// 获取第二个输入描述符的缩放因子
double fin2 = ((PyArray_SFloatDescr *)context->descriptors[1])->scaling;
// 获取输出描述符的缩放因子
double fout = ((PyArray_SFloatDescr *)context->descriptors[2])->scaling;
// 计算输入输出之间的缩放因子
double fact1 = fin1 / fout;
double fact2 = fin2 / fout;
// 检查第一个缩放因子是否有效
if (check_factor(fact1) < 0) {
return -1;
}
// 检查第二个缩放因子是否有效
if (check_factor(fact2) < 0) {
return -1;
}
// 获取第一个维度的大小
npy_intp N = dimensions[0];
// 获取输入数组的指针
char *in1 = data[0];
char *in2 = data[1];
// 获取输出数组的指针
char *out = data[2];
// 遍历数组进行加法运算
for (npy_intp i = 0; i < N; i++) {
// 将输入数组中的双精度浮点数按比例相加,结果存入输出数组中
*(double *)out = (*(double *)in1 * fact1) + (*(double *)in2 * fact2);
// 更新输入数组和输出数组的指针位置
in1 += strides[0];
in2 += strides[1];
out += strides[2];
}
return 0;
}
static NPY_CASTING
/*
* 根据给定的描述符解析添加单精度浮点数,并解决描述符。
* 如果没有给定输出描述符,则使用常见实例。
*/
add_sfloats_resolve_descriptors(
PyArrayMethodObject *NPY_UNUSED(self),
PyArray_DTypeMeta *NPY_UNUSED(dtypes[3]),
PyArray_Descr *given_descrs[3],
PyArray_Descr *loop_descrs[3],
npy_intp *NPY_UNUSED(view_offset))
{
/*
* 如果没有给定输出描述符,则使用常见实例:
*/
if (given_descrs[2] == NULL) {
// 使用给定的输入描述符创建一个共享的单精度浮点数描述符
loop_descrs[2] = sfloat_common_instance(
given_descrs[0], given_descrs[1]);
if (loop_descrs[2] == 0) {
return -1; // 失败返回
}
}
else {
// 增加引用计数以使用给定的输出描述符
Py_INCREF(given_descrs[2]);
loop_descrs[2] = given_descrs[2];
}
// 增加引用计数以使用给定的输入描述符
Py_INCREF(given_descrs[0]);
loop_descrs[0] = given_descrs[0];
Py_INCREF(given_descrs[1]);
loop_descrs[1] = given_descrs[1];
/* 如果比例因子不匹配,我们在ufunc内部进行隐式转换! */
double fin1 = ((PyArray_SFloatDescr *)loop_descrs[0])->scaling;
double fin2 = ((PyArray_SFloatDescr *)loop_descrs[1])->scaling;
double fout = ((PyArray_SFloatDescr *)loop_descrs[2])->scaling;
// 如果输入和输出的比例因子完全匹配,则不需要转换
if (fin1 == fout && fin2 == fout) {
return NPY_NO_CASTING;
}
// 如果输入的绝对值和输出的绝对值相匹配,则可以进行等价转换
if (npy_fabs(fin1) == npy_fabs(fout) && npy_fabs(fin2) == npy_fabs(fout)) {
return NPY_EQUIV_CASTING;
}
// 否则,进行相同类型的转换
return NPY_SAME_KIND_CASTING;
}
/*
* 使用 "PyUFunc_AddWrappingLoop" API 定义 hypot 循环。
* 目前仅用于映射到双精度 hypot 循环。
*/
static int
translate_given_descrs_to_double(
int nin, int nout, PyArray_DTypeMeta *const wrapped_dtypes[],
PyArray_Descr *const given_descrs[], PyArray_Descr *new_descrs[])
{
assert(nin == 2 && nout == 1);
for (int i = 0; i < 3; i++) {
if (given_descrs[i] == NULL) {
new_descrs[i] = NULL;
}
else {
// 将给定的描述符转换为双精度描述符
new_descrs[i] = PyArray_DescrFromType(NPY_DOUBLE);
}
}
return 0;
}
/*
* 将给定的描述符转换为循环描述符。
*/
static int
translate_loop_descrs(
int nin, int nout, PyArray_DTypeMeta *const new_dtypes[],
PyArray_Descr *const given_descrs[],
PyArray_Descr *NPY_UNUSED(original_descrs[]),
PyArray_Descr *loop_descrs[])
{
assert(nin == 2 && nout == 1);
// 使用给定的输入描述符创建共享的单精度浮点数描述符
loop_descrs[0] = sfloat_common_instance(
given_descrs[0], given_descrs[1]);
if (loop_descrs[0] == 0) {
return -1; // 失败返回
}
// 增加引用计数以使用共享的描述符
Py_INCREF(loop_descrs[0]);
loop_descrs[1] = loop_descrs[0];
Py_INCREF(loop_descrs[0]);
loop_descrs[2] = loop_descrs[0];
return 0;
}
/*
* 根据给定的 ufunc 名称获取 ufunc 对象。
*/
static PyObject *
sfloat_get_ufunc(const char *ufunc_name)
{
// 导入 numpy 模块
PyObject *mod = PyImport_ImportModule("numpy");
if (mod == NULL) {
return NULL; // 导入失败
}
// 获取指定名称的 ufunc 对象
PyObject *ufunc = PyObject_GetAttrString(mod, ufunc_name);
Py_DECREF(mod);
// 检查获取的对象是否为 ufunc 类型
if (!PyObject_TypeCheck(ufunc, &PyUFunc_Type)) {
Py_DECREF(ufunc);
// 如果不是 ufunc 类型,则抛出类型错误异常
PyErr_Format(PyExc_TypeError,
"numpy.%s was not a ufunc!", ufunc_name);
return NULL;
}
// 返回获取到的 ufunc 对象
return ufunc;
}
# 返回 ufunc 变量的值
return ufunc;
/*
* Add a new loop to the specified ufunc for floating-point addition.
* This function retrieves the ufunc object by name and prepares the necessary
* information to add a new loop for the given data types.
*/
static int
sfloat_add_loop(const char *ufunc_name,
PyArray_DTypeMeta *dtypes[3], PyObject *meth_or_promoter)
{
// 获取指定名称的ufunc对象
PyObject *ufunc = sfloat_get_ufunc(ufunc_name);
if (ufunc == NULL) {
return -1;
}
// 创建一个包含三个数据类型的元组
PyObject *dtype_tup = PyArray_TupleFromItems(3, (PyObject **)dtypes, 1);
if (dtype_tup == NULL) {
Py_DECREF(ufunc);
return -1;
}
// 打包类型元组和方法/推广器成为一个元组info
PyObject *info = PyTuple_Pack(2, dtype_tup, meth_or_promoter);
Py_DECREF(dtype_tup);
if (info == NULL) {
Py_DECREF(ufunc);
return -1;
}
// 添加循环到ufunc对象中
int res = PyUFunc_AddLoop((PyUFuncObject *)ufunc, info, 0);
Py_DECREF(ufunc);
Py_DECREF(info);
return res;
}
/*
* Add a wrapping loop to the specified ufunc for floating-point addition.
* This function retrieves the ufunc object by name and adds a wrapping loop
* using the provided data types and their corresponding wrapped versions.
*/
static int
sfloat_add_wrapping_loop(const char *ufunc_name, PyArray_DTypeMeta *dtypes[3])
{
// 获取指定名称的ufunc对象
PyObject *ufunc = sfloat_get_ufunc(ufunc_name);
if (ufunc == NULL) {
return -1;
}
// 准备包裹的数据类型为双精度浮点类型
PyArray_DTypeMeta *double_dt = &PyArray_DoubleDType;
PyArray_DTypeMeta *wrapped_dtypes[3] = {double_dt, double_dt, double_dt};
// 添加包裹循环到ufunc对象中
int res = PyUFunc_AddWrappingLoop(
ufunc, dtypes, wrapped_dtypes, &translate_given_descrs_to_double,
&translate_loop_descrs);
Py_DECREF(ufunc);
return res;
}
/*
* Add promoters to convert normal floats to scaled floats.
* This function is used to promote data types for multiplication operations.
*/
static int
promote_to_sfloat(PyUFuncObject *NPY_UNUSED(ufunc),
PyArray_DTypeMeta *const NPY_UNUSED(dtypes[3]),
PyArray_DTypeMeta *const signature[3],
PyArray_DTypeMeta *new_dtypes[3])
{
// 遍历每个数据类型,将其推广为单精度浮点类型
for (int i = 0; i < 3; i++) {
PyArray_DTypeMeta *new = &PyArray_SFloatDType;
if (signature[i] != NULL) {
new = signature[i];
}
Py_INCREF(new);
new_dtypes[i] = new;
}
return 0;
}
/*
* Initialize custom ufuncs for single-precision floating-point operations.
* This function initializes and registers ufuncs for multiplication and addition
* of single-precision floating-point numbers.
*/
static int
sfloat_init_ufuncs(void) {
// 定义三个单精度浮点类型的数据类型元组
PyArray_DTypeMeta *dtypes[3] = {
&PyArray_SFloatDType, &PyArray_SFloatDType, &PyArray_SFloatDType};
// 定义三个PyType_Slot槽
PyType_Slot slots[3] = {{0, NULL}};
// 定义一个PyArrayMethod_Spec结构体用于描述方法
PyArrayMethod_Spec spec = {
.nin = 2,
.nout =1,
.dtypes = dtypes,
.slots = slots,
};
// 添加乘法方法的解析描述符和循环函数
spec.name = "sfloat_multiply";
spec.casting = NPY_NO_CASTING;
slots[0].slot = NPY_METH_resolve_descriptors;
slots[0].pfunc = &multiply_sfloats_resolve_descriptors;
slots[1].slot = NPY_METH_strided_loop;
slots[1].pfunc = &multiply_sfloats;
// 创建一个PyBoundArrayMethodObject对象
PyBoundArrayMethodObject *bmeth = PyArrayMethod_FromSpec_int(&spec, 0);
if (bmeth == NULL) {
return -1;
}
// 添加乘法方法的循环到ufunc对象中
int res = sfloat_add_loop("multiply",
bmeth->dtypes, (PyObject *)bmeth->method);
Py_DECREF(bmeth);
if (res < 0) {
return -1;
}
// 添加加法方法的解析描述符和循环函数
spec.name = "sfloat_add";
spec.casting = NPY_SAME_KIND_CASTING;
slots[0].slot = NPY_METH_resolve_descriptors;
slots[0].pfunc = &add_sfloats_resolve_descriptors;
slots[1].slot = NPY_METH_strided_loop;
slots[1].pfunc = &add_sfloats;
// 创建一个PyBoundArrayMethodObject对象
bmeth = PyArrayMethod_FromSpec_int(&spec, 0);
if (bmeth == NULL) {
return -1;
}
// 添加加法方法的循环到ufunc对象中
res = sfloat_add_loop("add",
bmeth->dtypes, (PyObject *)bmeth->method);
Py_DECREF(bmeth);
if (res < 0) {
return -1;
}
return 0;
}
# 使用给定的规格创建一个整数类型的数组方法对象
bmeth = PyArrayMethod_FromSpec_int(&spec, 0);
if (bmeth == NULL) {
return -1;
}
# 调用特定方法名称为"add"的浮点数加法循环,并传入方法对象的数据类型和方法对象本身作为参数
res = sfloat_add_loop("add",
bmeth->dtypes, (PyObject *)bmeth->method);
# 减少方法对象的引用计数
Py_DECREF(bmeth);
if (res < 0) {
return -1;
}
# 注意:如果类型的缩放因子可以为负数,则包装实际上不正确
if (sfloat_add_wrapping_loop("hypot", dtypes) < 0) {
return -1;
}
"""
* 为双精度乘法的两个方向添加提升器。
"""
# 创建一个指向双精度数据类型的指针
PyArray_DTypeMeta *double_DType = &PyArray_DoubleDType;
# 创建一个包含提升到单精度浮点数、双精度和空指针的数据类型元数据数组
PyArray_DTypeMeta *promoter_dtypes[3] = {
&PyArray_SFloatDType, double_DType, NULL};
# 创建一个新的 Python Capsule 对象,用于封装提升到单精度浮点数的函数
PyObject *promoter = PyCapsule_New(
&promote_to_sfloat, "numpy._ufunc_promoter", NULL);
if (promoter == NULL) {
return -1;
}
# 调用特定方法名称为"multiply"的浮点数乘法循环,并传入提升器的数据类型数组和提升器本身作为参数
res = sfloat_add_loop("multiply", promoter_dtypes, promoter);
if (res < 0) {
Py_DECREF(promoter);
return -1;
}
# 调整提升器的数据类型数组,反向传入参数,并再次调用浮点数乘法循环
promoter_dtypes[0] = double_DType;
promoter_dtypes[1] = &PyArray_SFloatDType;
res = sfloat_add_loop("multiply", promoter_dtypes, promoter);
# 减少提升器对象的引用计数
Py_DECREF(promoter);
if (res < 0) {
return -1;
}
# 返回操作成功的标志
return 0;
"""
/*
* Python entry point, exported via `umathmodule.h` and `multiarraymodule.c`.
* TODO: Should be moved when the necessary API is not internal anymore.
*/
"""
# 检查全局变量以确保未初始化时获取单精度浮点数据类型
NPY_NO_EXPORT PyObject *
get_sfloat_dtype(PyObject *NPY_UNUSED(mod), PyObject *NPY_UNUSED(args))
{
if (npy_thread_unsafe_state.get_sfloat_dtype_initialized) {
# 如果已经初始化,增加对单精度浮点数据类型的引用计数并返回它
Py_INCREF(&PyArray_SFloatDType);
return (PyObject *)&PyArray_SFloatDType;
}
# 将单精度浮点数据类型的基类设置为描述符类型
PyArray_SFloatDType.super.ht_type.tp_base = &PyArrayDescr_Type;
# 准备单精度浮点数据类型对象,如果失败则返回空指针
if (PyType_Ready((PyTypeObject *)&PyArray_SFloatDType) < 0) {
return NULL;
}
# 创建一个新的字典来存储类型的转换实现
NPY_DT_SLOTS(&PyArray_SFloatDType)->castingimpls = PyDict_New();
if (NPY_DT_SLOTS(&PyArray_SFloatDType)->castingimpls == NULL) {
return NULL;
}
# 使用单精度浮点数据类型初始化一个新的 Python 对象
PyObject *o = PyObject_Init(
(PyObject *)&SFloatSingleton, (PyTypeObject *)&PyArray_SFloatDType);
if (o == NULL) {
return NULL;
}
# 初始化单精度浮点类型的类型转换
if (sfloat_init_casts() < 0) {
return NULL;
}
# 初始化单精度浮点类型的通用函数
if (sfloat_init_ufuncs() < 0) {
return NULL;
}
# 将状态标记为已初始化
npy_thread_unsafe_state.get_sfloat_dtype_initialized = NPY_TRUE;
# 返回单精度浮点数据类型对象
return (PyObject *)&PyArray_SFloatDType;
}
.\numpy\numpy\_core\src\umath\_struct_ufunc_tests.c
/*
* struct_ufunc_test.c
* This is the C code for creating your own
* NumPy ufunc for a structured array dtype.
*
* Details explaining the Python-C API can be found under
* 'Extending and Embedding' and 'Python/C API' at
* docs.python.org .
*/
// 定义一个静态函数,用于将三个 uint64 类型的数组相加
static void add_uint64_triplet(char **args,
npy_intp const *dimensions,
npy_intp const* steps,
void* data)
{
npy_intp i;
npy_intp is1=steps[0]; // 第一个输入数组的步长
npy_intp is2=steps[1]; // 第二个输入数组的步长
npy_intp os=steps[2]; // 输出数组的步长
npy_intp n=dimensions[0]; // 数组的维度大小
npy_uint64 *x, *y, *z; // 定义指向输入和输出数组的指针
char *i1=args[0]; // 第一个输入数组的起始地址
char *i2=args[1]; // 第二个输入数组的起始地址
char *op=args[2]; // 输出数组的起始地址
for (i = 0; i < n; i++) {
// 将输入数组的地址强制转换为 uint64 类型的指针
x = (npy_uint64*)i1;
y = (npy_uint64*)i2;
z = (npy_uint64*)op;
// 执行相加操作,并将结果存入输出数组
z[0] = x[0] + y[0];
z[1] = x[1] + y[1];
z[2] = x[2] + y[2];
// 更新输入和输出数组的地址,移动到下一个元素
i1 += is1;
i2 += is2;
op += os;
}
}
// 定义一个 Python 函数,用于注册自定义的 ufunc
static PyObject*
register_fail(PyObject* NPY_UNUSED(self), PyObject* NPY_UNUSED(args))
{
PyObject *add_triplet; // 定义一个 PyObject 类型的对象,用于存储 ufunc
PyObject *dtype_dict; // 用于存储结构化数据类型的字典对象
PyArray_Descr *dtype; // 用于存储结构化数据类型的描述符
PyArray_Descr *dtypes[3]; // 定义一个数组,存储三个结构化数据类型的描述符
int retval; // 用于存储函数调用返回值的变量
// 创建一个 ufunc 对象,名称为 "add_triplet",无文档字符串
add_triplet = PyUFunc_FromFuncAndData(NULL, NULL, NULL, 0, 2, 1,
PyUFunc_None, "add_triplet",
"add_triplet_docstring", 0);
// 创建一个包含结构化数据类型信息的字典对象
dtype_dict = Py_BuildValue("[(s, s), (s, s), (s, s)]",
"f0", "u8", "f1", "u8", "f2", "u8");
// 将 dtype_dict 转换为 PyArray_Descr 结构,并存储在 dtype 中
PyArray_DescrConverter(dtype_dict, &dtype);
// 释放 dtype_dict 占用的内存
Py_DECREF(dtype_dict);
// 将 dtype 分别赋值给 dtypes 数组中的三个元素
dtypes[0] = dtype;
dtypes[1] = dtype;
dtypes[2] = dtype;
// 将 add_uint64_triplet 函数注册到 add_triplet ufunc 中
retval = PyUFunc_RegisterLoopForDescr((PyUFuncObject *)add_triplet,
dtype,
&add_uint64_triplet,
dtypes,
NULL);
// 如果注册失败,则释放内存并返回 NULL
if (retval < 0) {
Py_DECREF(add_triplet);
Py_DECREF(dtype);
return NULL;
}
// 再次尝试注册,以确保成功
retval = PyUFunc_RegisterLoopForDescr((PyUFuncObject *)add_triplet,
dtype,
&add_uint64_triplet,
dtypes,
NULL);
// 释放内存
Py_DECREF(add_triplet);
Py_DECREF(dtype);
// 如果再次注册失败,则返回 NULL
if (retval < 0) {
return NULL;
}
// 注册成功,返回 Py_None
Py_RETURN_NONE;
}
// 定义模块中的方法列表
static PyMethodDef StructUfuncTestMethods[] = {
{"register_fail",
register_fail,
METH_NOARGS, NULL}, // 注册失败时调用的方法
{NULL, NULL, 0, NULL} // 方法列表结束
};
// 定义模块的结构体
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT, // 模块定义的头部初始化
"_struct_ufunc_tests", // 模块名称
NULL, // 模块文档字符串
-1, // 模块状态
StructUfuncTestMethods, // 模块中定义的方法列表
NULL, // 模块的全局状态
NULL, // 模块中的内存分配函数
NULL, // 模块中的内存释放函数
NULL // 模块中的状态清理函数
};
// 模块初始化函数
PyMODINIT_FUNC PyInit__struct_ufunc_tests(void)
{
PyObject *m, *add_triplet, *d;
// 创建一个新模块对象
m = PyModule_Create(&moduledef);
// 返回创建的模块对象
return m;
}
// 声明 PyObject 类型的变量 dtype_dict,用于存储描述符字典
PyObject *dtype_dict;
// 声明 PyArray_Descr 类型的变量 dtype,用于存储数组描述符
PyArray_Descr *dtype;
// 声明 PyArray_Descr 类型的数组 dtypes,用于存储多个数组描述符
PyArray_Descr *dtypes[3];
// 创建 Python 模块对象 m,使用给定的 moduledef 结构体
m = PyModule_Create(&moduledef);
// 如果创建模块失败,返回 NULL
if (m == NULL) {
return NULL;
}
// 导入 NumPy 的数组支持模块
import_array();
// 导入 NumPy 的数学函数支持模块
import_umath();
// 创建一个通用函数对象 add_triplet,用于执行三个输入操作数的特定功能
add_triplet = PyUFunc_FromFuncAndData(NULL, NULL, NULL, 0, 2, 1,
PyUFunc_None, "add_triplet",
"add_triplet_docstring", 0);
// 使用 Py_BuildValue 函数创建一个 Python 字典对象 dtype_dict,包含三个键值对
dtype_dict = Py_BuildValue("[(s, s), (s, s), (s, s)]",
"f0", "u8", "f1", "u8", "f2", "u8");
// 将 dtype_dict 转换为 PyArray_Descr 结构体,存储在 dtype 中
PyArray_DescrConverter(dtype_dict, &dtype);
// 释放 dtype_dict 对象的引用计数
Py_DECREF(dtype_dict);
// 将同一个 dtype 描述符分配给数组 dtypes 的所有三个元素
dtypes[0] = dtype;
dtypes[1] = dtype;
dtypes[2] = dtype;
// 将描述符 dtype 注册到通用函数 add_triplet 中,并指定用于每个操作数的描述符数组 dtypes
PyUFunc_RegisterLoopForDescr((PyUFuncObject *)add_triplet,
dtype,
&add_uint64_triplet,
dtypes,
NULL);
// 释放描述符 dtype 对象的引用计数
Py_DECREF(dtype);
// 获取模块 m 的字典对象
d = PyModule_GetDict(m);
// 将 add_triplet 对象添加到模块字典 d 中,键为 "add_triplet"
PyDict_SetItemString(d, "add_triplet", add_triplet);
// 释放 add_triplet 对象的引用计数
Py_DECREF(add_triplet);
// 返回创建的 Python 模块对象 m
return m;
}
注释:
.\numpy\numpy\_core\src\umath\_umath_tests.dispatch.c
/**
* Testing the utilities of the CPU dispatcher
*
* @targets $werror baseline
* SSE2 SSE41 AVX2
* VSX VSX2 VSX3
* NEON ASIMD ASIMDHP
*/
// 包含 Python 核心头文件
// 包含 NumPy 的 CPU 分发相关头文件
// 如果未禁用优化,则包含特定的优化测试分发头文件
// 声明并定义 CPU 分发相关函数和变量
NPY_CPU_DISPATCH_DECLARE(const char *_umath_tests_dispatch_func, (void))
NPY_CPU_DISPATCH_DECLARE(extern const char *_umath_tests_dispatch_var)
NPY_CPU_DISPATCH_DECLARE(void _umath_tests_dispatch_attach, (PyObject *list))
// 初始化 CPU 分发变量并定义相应函数
const char *NPY_CPU_DISPATCH_CURFX(_umath_tests_dispatch_var) = NPY_TOSTRING(NPY_CPU_DISPATCH_CURFX(var));
const char *NPY_CPU_DISPATCH_CURFX(_umath_tests_dispatch_func)(void)
{
static const char *current = NPY_TOSTRING(NPY_CPU_DISPATCH_CURFX(func));
return current;
}
// 将当前 CPU 分发函数名称添加到给定的 Python 列表中
void NPY_CPU_DISPATCH_CURFX(_umath_tests_dispatch_attach)(PyObject *list)
{
PyObject *item = PyUnicode_FromString(NPY_TOSTRING(NPY_CPU_DISPATCH_CURFX(func)));
if (item) {
PyList_Append(list, item);
Py_DECREF(item);
}
}
.\numpy\numpy\_core\src\_simd\_simd.c
// 定义函数:获取当前浮点状态的 Python 对象
static PyObject *
get_floatstatus(PyObject* NPY_UNUSED(self), PyObject *NPY_UNUSED(args))
{
// 调用 numpy 库函数获取当前浮点状态并返回相应的 Python 对象
return PyLong_FromLong(npy_get_floatstatus());
}
// 定义函数:清除当前浮点状态
static PyObject *
clear_floatstatus(PyObject* NPY_UNUSED(self), PyObject *NPY_UNUSED(args))
{
// 调用 numpy 库函数清除当前浮点状态
npy_clear_floatstatus();
// 直接返回 None 对象
Py_RETURN_NONE;
}
// 定义模块方法列表
static PyMethodDef _simd_methods[] = {
{"get_floatstatus", get_floatstatus, METH_NOARGS, NULL}, // 注册获取浮点状态函数
{"clear_floatstatus", clear_floatstatus, METH_NOARGS, NULL}, // 注册清除浮点状态函数
{NULL, NULL, 0, NULL} // 结束方法列表的标记
};
// 模块初始化函数
PyMODINIT_FUNC PyInit__simd(void)
{
// 定义模块结构体
static struct PyModuleDef defs = {
.m_base = PyModuleDef_HEAD_INIT, // 设置模块结构的基本属性
.m_name = "numpy._core._simd", // 模块名称
.m_size = -1, // 模块大小
.m_methods = _simd_methods // 模块方法列表
};
// 初始化 CPU 相关功能,若失败则返回 NULL
if (npy_cpu_init() < 0) {
return NULL;
}
// 创建 Python 模块对象,如果失败则返回 NULL
PyObject *m = PyModule_Create(&defs);
if (m == NULL) {
return NULL;
}
// 创建一个空的字典对象用于存储目标特性
PyObject *targets = PyDict_New();
if (targets == NULL) {
goto err; // 如果创建失败则跳转到错误处理
}
// 将 targets 字典对象添加到模块中,如果失败则释放 targets 并跳转到错误处理
if (PyModule_AddObject(m, "targets", targets) < 0) {
Py_DECREF(targets);
goto err;
}
// 宏定义,用于根据特性测试情况添加模块
{ \
PyObject *simd_mod; \
if (!TESTED_FEATURES) { \
Py_INCREF(Py_None); \
simd_mod = Py_None; \
} else { \
simd_mod = NPY_CAT(simd_create_module_, TARGET_NAME)(); \
if (simd_mod == NULL) { \
goto err; \
} \
} \
const char *target_name = NPY_TOSTRING(TARGET_NAME); \
if (PyDict_SetItemString(targets, target_name, simd_mod) < 0) { \
Py_DECREF(simd_mod); \
goto err; \
} \
Py_INCREF(simd_mod); \
if (PyModule_AddObject(m, target_name, simd_mod) < 0) { \
Py_DECREF(simd_mod); \
goto err; \
} \
}
// ATTACH_MODULE 宏的作用是根据特性情况添加模块对象到 targets 字典和模块中
// 返回创建的模块对象
return m;
// 错误处理代码块
err:
// 在错误处理时释放所有已分配的资源,并返回 NULL
Py_XDECREF(m);
return NULL;
}
{ \
// 创建名为 baseline 的 Python 模块对象
PyObject *simd_mod = simd_create_module(); \
// 如果创建失败,则跳转到错误处理标签 err
if (simd_mod == NULL) { \
goto err; \
} \
// 将 baseline 模块对象添加到 targets 字典中,如果失败则跳转到 err
if (PyDict_SetItemString(targets, "baseline", simd_mod) < 0) { \
Py_DECREF(simd_mod); \
goto err; \
} \
// 增加 baseline 模块对象的引用计数
Py_INCREF(simd_mod); \
// 将 baseline 模块对象添加到 m 模块中,如果失败则跳转到 err
if (PyModule_AddObject(m, "baseline", simd_mod) < 0) { \
Py_DECREF(simd_mod); \
goto err; \
} \
}
// 使用 NPY_MTARGETS_CONF_DISPATCH 宏调用 ATTACH_MODULE 宏和 MAKE_MSVC_HAPPY 宏
NPY_MTARGETS_CONF_DISPATCH(NPY_CPU_HAVE, ATTACH_MODULE, MAKE_MSVC_HAPPY)
// 使用 NPY_MTARGETS_CONF_BASELINE 宏调用 ATTACH_BASELINE_MODULE 宏和 MAKE_MSVC_HAPPY 宏
NPY_MTARGETS_CONF_BASELINE(ATTACH_BASELINE_MODULE, MAKE_MSVC_HAPPY)
// 使用 NPY__CPU_DISPATCH_CALL 宏调用 ATTACH_MODULE 宏和 MAKE_MSVC_HAPPY 宏
NPY__CPU_DISPATCH_CALL(NPY_CPU_HAVE, ATTACH_MODULE, MAKE_MSVC_HAPPY)
// 使用 NPY__CPU_DISPATCH_BASELINE_CALL 宏调用 ATTACH_BASELINE_MODULE 宏和 MAKE_MSVC_HAPPY 宏
NPY__CPU_DISPATCH_BASELINE_CALL(ATTACH_BASELINE_MODULE, MAKE_MSVC_HAPPY)
// 返回模块对象 m
return m;
err:
Py_DECREF(m);
return NULL;
}
.\numpy\numpy\_core\src\_simd\_simd.h
/**
* A module to expose the NumPy C SIMD vectorization interface "NPYV" for testing purposes.
*
* Please keep this module independent from other c-extension modules,
* since NPYV intrinsics may be involved in their functionality,
* which increases the degree of complexity in tracking and detecting errors.
*
* TODO: Add an independent sphinx doc.
*
* Please add any new NPYV intrinsics in '_simd.dispatch.c.src'.
*/
// autogenerated, required for CPU dispatch macros
/**
* Declare a hidden visibility function 'simd_create_module' to create a new module
* for each required optimization which contains all NPYV intrinsics.
*
* If a required optimization is not supported by NPYV, the module still provides
* access to NPYV constants NPY_SIMD, NPY_SIMD_F64, and NPY_SIMD_WIDTH but without
* any intrinsics.
*/
NPY_CPU_DISPATCH_DECLARE(NPY_VISIBILITY_HIDDEN PyObject *simd_create_module, (void))
.\numpy\numpy\_core\strings.py
"""
This module contains a set of functions for vectorized string
operations.
"""
import sys
import numpy as np
from numpy import (
equal, not_equal, less, less_equal, greater, greater_equal,
add, multiply as _multiply_ufunc,
)
from numpy._core.multiarray import _vec_string
from numpy._core.umath import (
isalpha,
isdigit,
isspace,
isalnum,
islower,
isupper,
istitle,
isdecimal,
isnumeric,
str_len,
find as _find_ufunc,
rfind as _rfind_ufunc,
index as _index_ufunc,
rindex as _rindex_ufunc,
count as _count_ufunc,
startswith as _startswith_ufunc,
endswith as _endswith_ufunc,
_lstrip_whitespace,
_lstrip_chars,
_rstrip_whitespace,
_rstrip_chars,
_strip_whitespace,
_strip_chars,
_replace,
_expandtabs_length,
_expandtabs,
_center,
_ljust,
_rjust,
_zfill,
_partition,
_partition_index,
_rpartition,
_rpartition_index,
)
__all__ = [
"equal", "not_equal", "less", "less_equal", "greater", "greater_equal",
"add", "multiply", "isalpha", "isdigit", "isspace", "isalnum", "islower",
"isupper", "istitle", "isdecimal", "isnumeric", "str_len", "find",
"rfind", "index", "rindex", "count", "startswith", "endswith", "lstrip",
"rstrip", "strip", "replace", "expandtabs", "center", "ljust", "rjust",
"zfill", "partition", "rpartition",
"upper", "lower", "swapcase", "capitalize", "title",
"mod", "decode", "encode", "translate",
]
MAX = np.iinfo(np.int64).max
def _get_num_chars(a):
"""
Helper function that returns the number of characters per field in
a string or unicode array. This is to abstract out the fact that
for a unicode array this is itemsize / 4.
"""
if issubclass(a.dtype.type, np.str_):
return a.itemsize // 4
return a.itemsize
def _to_bytes_or_str_array(result, output_dtype_like):
"""
Helper function to cast a result back into an array
with the appropriate dtype if an object array must be used
as an intermediary.
"""
output_dtype_like = np.asarray(output_dtype_like)
if result.size == 0:
return result.astype(output_dtype_like.dtype)
ret = np.asarray(result.tolist())
if isinstance(output_dtype_like.dtype, np.dtypes.StringDType):
return ret.astype(type(output_dtype_like.dtype))
return ret.astype(type(output_dtype_like.dtype)(_get_num_chars(ret)))
def _clean_args(*args):
"""
Helper function for delegating arguments to Python string
functions.
Many of the Python string operations that have optional arguments
are handled by this function.
"""
newargs = []
for chk in args:
if chk is None:
break
newargs.append(chk)
return newargs
def multiply(a, i):
"""
Return (a * i), that is string multiple concatenation,
element-wise.
Values in ``i`` of less than 0 are treated as 0 (which yields an
empty string).
Parameters
----------
a : array_like, with ``StringDType``, ``bytes_`` or ``str_`` dtype
Input array containing strings or bytes to be multiplied.
i : array_like, with any integer dtype
Input array containing integers representing the number of times
each string in `a` should be repeated.
Returns
-------
out : ndarray
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
depending on input types. Contains the result of element-wise
string multiplication.
Raises
------
TypeError
If `i` contains a dtype that is not an integer.
MemoryError
If the resulting repeated strings exceed system memory.
Examples
--------
Provides examples of how the function operates with different inputs.
"""
a = np.asanyarray(a)
i = np.asanyarray(i)
if not np.issubdtype(i.dtype, np.integer):
raise TypeError(f"unsupported type {i.dtype} for operand 'i'")
i = np.maximum(i, 0)
if a.dtype.char == "T":
return a * i
a_len = str_len(a)
if np.any(a_len > sys.maxsize / np.maximum(i, 1)):
raise MemoryError("repeated string is too long")
buffersizes = a_len * i
out_dtype = f"{a.dtype.char}{buffersizes.max()}"
out = np.empty_like(a, shape=buffersizes.shape, dtype=out_dtype)
return _multiply_ufunc(a, i, out=out)
def mod(a, values):
"""
Return (a % i), that is pre-Python 2.6 string formatting
(interpolation), element-wise for a pair of array_likes of str
or unicode.
Parameters
----------
a : array_like, with `np.bytes_` or `np.str_` dtype
Input array containing strings or bytes to be formatted.
values : array_like of values
These values will be element-wise interpolated into the string.
Returns
-------
out : ndarray
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
depending on input types. Contains the result of element-wise
string formatting.
"""
return _to_bytes_or_str_array(
_vec_string(a, np.object_, '__mod__', (values,)), a)
def find(a, sub, start=0, end=None):
"""
For each element, return the lowest index in the string where
substring ``sub`` is found, such that ``sub`` is contained in the
range [``start``, ``end``).
Parameters
----------
a : array_like, with ``StringDType``, ``bytes_`` or ``str_`` dtype
Input array containing strings or bytes to search within.
sub : array_like, with `np.bytes_` or `np.str_` dtype
The substring to search for.
start, end : array_like, with any integer dtype, optional
The range to look in, interpreted as in slice notation.
Returns
-------
"""
return _vec_string(a, sub, 'find', (start, end))
-------
y : ndarray
Output array of ints
输出整数数组 `y`
See Also
--------
str.find
相关函数:str.find
Examples
--------
>>> a = np.array(["NumPy is a Python library"])
>>> np.strings.find(a, "Python")
array([11])
示例:在数组 `a` 中查找子字符串 "Python",返回位置索引数组 [11]
"""
end = end if end is not None else MAX
# 如果 `end` 不为 None,则使用 `end`;否则使用预定义的 `MAX` 值
return _find_ufunc(a, sub, start, end)
# 调用 `_find_ufunc` 函数,传递参数 `a`, `sub`, `start`, `end`,并返回其结果
# 返回数组中每个元素中指定子字符串最后出现的索引位置,查找范围为[start, end)。
def rfind(a, sub, start=0, end=None):
end = end if end is not None else MAX # 如果未提供end参数,则使用默认值MAX
return _rfind_ufunc(a, sub, start, end) # 调用内部的rfind函数进行实际查找
# 类似于find,但在子字符串未找到时引发ValueError异常。
def index(a, sub, start=0, end=None):
end = end if end is not None else MAX # 如果未提供end参数,则使用默认值MAX
return _index_ufunc(a, sub, start, end) # 调用内部的index函数进行实际查找
# 类似于rfind,但在子字符串未找到时引发ValueError异常。
def rindex(a, sub, start=0, end=None):
end = end if end is not None else MAX # 如果未提供end参数,则使用默认值MAX
return _rindex_ufunc(a, sub, start, end) # 调用内部的rindex函数进行实际查找
# 返回数组中每个元素中指定子字符串出现的非重叠次数,查找范围为[start, end)。
def count(a, sub, start=0, end=None):
end = end if end is not None else MAX # 如果未提供end参数,则使用默认值MAX
return _count_ufunc(a, sub, start, end) # 调用内部的count函数进行实际计数
# 使用 numpy 库中的字符串处理函数 np.strings.count 对输入的字符串数组进行计数操作
array([3, 1, 1])
# 对字符串数组 c 中的每个字符串计算包含 'aA' 的次数,返回结果数组
>>> np.strings.count(c, 'aA')
array([3, 1, 0])
# 对字符串数组 c 中的每个字符串,在指定范围 [start, end) 内计算包含 'A' 的次数,返回结果数组
>>> np.strings.count(c, 'A', start=1, end=4)
array([2, 1, 1])
# 对字符串数组 c 中的每个字符串,在指定范围 [start, end) 内计算包含 'A' 的次数,返回结果数组
>>> np.strings.count(c, 'A', start=1, end=3)
# 如果 end 未指定,则使用预定义的 MAX 值作为结束位置
array([1, 0, 0])
"""
end = end if end is not None else MAX
return _count_ufunc(a, sub, start, end)
def startswith(a, prefix, start=0, end=None):
"""
Returns a boolean array which is `True` where the string element
in ``a`` starts with ``prefix``, otherwise `False`.
Parameters
----------
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
输入数组,元素可以是字符串类型,字节类型或者字符串
prefix : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
要检查的前缀,可以是字符串类型,字节类型或者字符串
start, end : array_like, with any integer dtype
开始和结束位置的索引,用于指定检查的范围
Returns
-------
out : ndarray
布尔类型的输出数组,表示每个元素是否以指定前缀开头
See Also
--------
str.startswith
Python 内置函数 str.startswith 的文档参考
"""
end = end if end is not None else MAX
return _startswith_ufunc(a, prefix, start, end)
def endswith(a, suffix, start=0, end=None):
"""
Returns a boolean array which is `True` where the string element
in ``a`` ends with ``suffix``, otherwise `False`.
Parameters
----------
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
输入数组,元素可以是字符串类型,字节类型或者字符串
suffix : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
要检查的后缀,可以是字符串类型,字节类型或者字符串
start, end : array_like, with any integer dtype
开始和结束位置的索引,用于指定检查的范围
Returns
-------
out : ndarray
布尔类型的输出数组,表示每个元素是否以指定后缀结尾
See Also
--------
str.endswith
Python 内置函数 str.endswith 的文档参考
Examples
--------
示例用法演示如何使用 np.strings.endswith 函数:
>>> s = np.array(['foo', 'bar'])
>>> s
array(['foo', 'bar'], dtype='<U3')
>>> np.strings.endswith(s, 'ar')
array([False, True])
>>> np.strings.endswith(s, 'a', start=1, end=2)
array([False, True])
"""
end = end if end is not None else MAX
return _endswith_ufunc(a, suffix, start, end)
def decode(a, encoding=None, errors=None):
r"""
Calls :meth:`bytes.decode` element-wise.
The set of available codecs comes from the Python standard library,
and may be extended at runtime. For more information, see the
:mod:`codecs` module.
Parameters
----------
a : array_like, with ``bytes_`` dtype
输入数组,元素必须是字节类型
encoding : str, optional
字符串编码的名称,可选参数
errors : str, optional
指定如何处理解码错误的字符串,可选参数
Returns
-------
out : ndarray
解码后的字符串数组
See Also
--------
:py:meth:`bytes.decode`
Python 内置函数 bytes.decode 的文档参考
Notes
-----
结果的数据类型取决于指定的编码格式。
Examples
--------
示例用法演示如何使用 np.strings.decode 函数:
>>> c = np.array([b'\x81\xc1\x81\xc1\x81\xc1', b'@@\x81\xc1@@',
... b'\x81\x82\xc2\xc1\xc2\x82\x81'])
>>> c
array([b'\x81\xc1\x81\xc1\x81\xc1', b'@@\x81\xc1@@',
b'\x81\x82\xc2\xc1\xc2\x82\x81'], dtype='|S7')
>>> np.strings.decode(c, encoding='cp037')
array(['aAaAaA', ' aA ', 'abBABba'], dtype='<U7')
"""
return _to_bytes_or_str_array(
_vec_string(a, np.object_, 'decode', _clean_args(encoding, errors)),
np.str_(''))
Calls :meth:`str.encode` element-wise.
The set of available codecs comes from the Python standard library,
and may be extended at runtime. For more information, see the
:mod:`codecs` module.
Parameters
----------
a : array_like, with ``StringDType`` or ``str_`` dtype
encoding : str, optional
The name of an encoding
errors : str, optional
Specifies how to handle encoding errors
Returns
-------
out : ndarray
See Also
--------
str.encode
Notes
-----
The type of the result will depend on the encoding specified.
Examples
--------
>>> a = np.array(['aAaAaA', ' aA ', 'abBABba'])
>>> np.strings.encode(a, encoding='cp037')
array([b'\x81\xc1\x81\xc1\x81\xc1', b'@@\x81\xc1@@',
b'\x81\x82\xc2\xc1\xc2\x82\x81'], dtype='|S7')
"""
return _to_bytes_or_str_array(
_vec_string(a, np.object_, 'encode', _clean_args(encoding, errors)),
np.bytes_(b''))
# 调用 `_vec_string` 函数,对数组 `a` 的每个元素进行编码,返回字节或字符串数组。
# `_clean_args` 函数用于清理并处理编码和错误处理参数。
# 最终返回一个字节类型的 NumPy 数组。
# 将函数定义为一个名为 expandtabs 的函数,用于处理数组中的字符串元素,将其中的制表符替换为一定数量的空格
def expandtabs(a, tabsize=8):
"""
Return a copy of each string element where all tab characters are
replaced by one or more spaces.
Calls :meth:`str.expandtabs` element-wise.
Return a copy of each string element where all tab characters are
replaced by one or more spaces, depending on the current column
and the given `tabsize`. The column number is reset to zero after
each newline occurring in the string. This doesn't understand other
non-printing characters or escape sequences.
Parameters
----------
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
Input array
tabsize : int, optional
Replace tabs with `tabsize` number of spaces. If not given defaults
to 8 spaces.
Returns
-------
out : ndarray
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
depending on input type
See Also
--------
str.expandtabs
Examples
--------
>>> a = np.array(['\t\tHello\tworld'])
>>> np.strings.expandtabs(a, tabsize=4) # doctest: +SKIP
array([' Hello world'], dtype='<U21') # doctest: +SKIP
"""
# 将输入的 a 转换为 numpy 数组
a = np.asanyarray(a)
# 将输入的 tabsize 转换为 numpy 数组
tabsize = np.asanyarray(tabsize)
# 如果 a 的 dtype 是 "T" 类型
if a.dtype.char == "T":
# 调用内部函数 _expandtabs 处理 a
return _expandtabs(a, tabsize)
# 计算每个字符串元素经过扩展后的长度
buffersizes = _expandtabs_length(a, tabsize)
# 构造输出的 dtype,长度为 buffersizes 中的最大值
out_dtype = f"{a.dtype.char}{buffersizes.max()}"
# 创建一个和 a 相同形状的空数组,dtype 为 out_dtype
out = np.empty_like(a, shape=buffersizes.shape, dtype=out_dtype)
# 调用 _expandtabs 函数处理 a,并将结果写入 out 中
return _expandtabs(a, tabsize, out=out)
# 将函数定义为一个名为 center 的函数,用于将数组中的字符串元素居中显示,可指定填充字符和输出宽度
def center(a, width, fillchar=' '):
"""
Return a copy of `a` with its elements centered in a string of
length `width`.
Parameters
----------
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
width : array_like, with any integer dtype
The length of the resulting strings, unless ``width < str_len(a)``.
fillchar : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
Optional padding character to use (default is space).
Returns
-------
out : ndarray
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
depending on input types
See Also
--------
str.center
Notes
-----
While it is possible for ``a`` and ``fillchar`` to have different dtypes,
passing a non-ASCII character in ``fillchar`` when ``a`` is of dtype "S"
is not allowed, and a ``ValueError`` is raised.
Examples
--------
>>> c = np.array(['a1b2','1b2a','b2a1','2a1b']); c
array(['a1b2', '1b2a', 'b2a1', '2a1b'], dtype='<U4')
>>> np.strings.center(c, width=9)
array([' a1b2 ', ' 1b2a ', ' b2a1 ', ' 2a1b '], dtype='<U9')
>>> np.strings.center(c, width=9, fillchar='*')
array(['***a1b2**', '***1b2a**', '***b2a1**', '***2a1b**'], dtype='<U9')
>>> np.strings.center(c, width=1)
array(['a1b2', '1b2a', 'b2a1', '2a1b'], dtype='<U4')
"""
# 将输入的 a 转换为 numpy 数组
a = np.asanyarray(a)
# 将 fillchar 转换为与 a 的数据类型相同的 NumPy 数组
fillchar = np.asanyarray(fillchar, dtype=a.dtype)
# 检查 fillchar 是否包含多个字符,如果是,则引发 TypeError 异常
if np.any(str_len(fillchar) != 1):
raise TypeError(
"The fill character must be exactly one character long")
# 如果 a 的数据类型为 'T'(字符串类型),则调用 _center 函数进行居中处理并返回结果
if a.dtype.char == "T":
return _center(a, width, fillchar)
# 计算 a 的字符串长度与指定宽度的最大值,并用于输出的数据类型
width = np.maximum(str_len(a), width)
out_dtype = f"{a.dtype.char}{width.max()}"
# 根据 a 的形状、指定宽度的形状和 fillchar 的形状,确定输出数组的形状
shape = np.broadcast_shapes(a.shape, width.shape, fillchar.shape)
# 创建一个与 a 类型相同的空数组,用于存储结果,并指定其形状和数据类型
out = np.empty_like(a, shape=shape, dtype=out_dtype)
# 调用 _center 函数,将 a、width、fillchar 和输出数组 out 传递给它,并返回结果
return _center(a, width, fillchar, out=out)
# 定义函数 ljust,用于将数组 `a` 中的元素左对齐,填充至长度为 `width` 的字符串中
def ljust(a, width, fillchar=' '):
"""
Return an array with the elements of `a` left-justified in a
string of length `width`.
Parameters
----------
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
输入数组,可以是字符串数组或字节串数组
width : array_like, with any integer dtype
结果字符串的长度,除非 `width < str_len(a)`。
fillchar : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
可选参数,用于填充的字符(默认为空格)。
Returns
-------
out : ndarray
返回一个数组,包含了左对齐后的字符串,其数据类型为 `StringDType`、`bytes_` 或 `str_`,取决于输入类型。
See Also
--------
str.ljust
Notes
-----
虽然 `a` 和 `fillchar` 可能具有不同的数据类型,
但在 `a` 的数据类型为 "S" 时,如果 `fillchar` 中包含非 ASCII 字符,
则会引发 `ValueError` 异常。
Examples
--------
>>> c = np.array(['aAaAaA', ' aA ', 'abBABba'])
>>> np.strings.ljust(c, width=3)
array(['aAaAaA', ' aA ', 'abBABba'], dtype='<U7')
>>> np.strings.ljust(c, width=9)
array(['aAaAaA ', ' aA ', 'abBABba '], dtype='<U9')
"""
# 将 `a` 转换为任意数组
a = np.asanyarray(a)
# 将 `fillchar` 转换为与 `a` 相同的数据类型的数组
fillchar = np.asanyarray(fillchar, dtype=a.dtype)
# 如果 `fillchar` 中有长度不为 1 的元素,则引发 TypeError 异常
if np.any(str_len(fillchar) != 1):
raise TypeError(
"The fill character must be exactly one character long")
# 如果 `a` 的数据类型为 "T",则调用 `_ljust` 函数来执行左对齐操作
if a.dtype.char == "T":
return _ljust(a, width, fillchar)
# 计算字符串数组 `a` 中每个字符串的最大长度与 `width` 的最大值作为新的 `width`
width = np.maximum(str_len(a), width)
# 计算输出数组的形状,以适应 `a`、`width` 和 `fillchar`
shape = np.broadcast_shapes(a.shape, width.shape, fillchar.shape)
# 根据结果数据类型创建一个新的输出数组
out_dtype = f"{a.dtype.char}{width.max()}"
out = np.empty_like(a, shape=shape, dtype=out_dtype)
# 调用 `_ljust` 函数执行左对齐操作,并将结果存储在 `out` 中
return _ljust(a, width, fillchar, out=out)
# 定义函数 rjust,用于将数组 `a` 中的元素右对齐,填充至长度为 `width` 的字符串中
def rjust(a, width, fillchar=' '):
"""
Return an array with the elements of `a` right-justified in a
string of length `width`.
Parameters
----------
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
输入数组,可以是字符串数组或字节串数组
width : array_like, with any integer dtype
结果字符串的长度,除非 `width < str_len(a)`。
fillchar : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
可选参数,用于填充的字符(默认为空格)。
Returns
-------
out : ndarray
返回一个数组,包含了右对齐后的字符串,其数据类型为 `StringDType`、`bytes_` 或 `str_`,取决于输入类型。
See Also
--------
str.rjust
Notes
-----
虽然 `a` 和 `fillchar` 可能具有不同的数据类型,
但在 `a` 的数据类型为 "S" 时,如果 `fillchar` 中包含非 ASCII 字符,
则会引发 `ValueError` 异常。
Examples
--------
>>> a = np.array(['aAaAaA', ' aA ', 'abBABba'])
>>> np.strings.rjust(a, width=3)
array(['aAaAaA', ' aA ', 'abBABba'], dtype='<U7')
>>> np.strings.rjust(a, width=9)
array([' aAaAaA', ' aA ', ' abBABba'], dtype='<U9')
"""
# 将 `a` 转换为任意数组
a = np.asanyarray(a)
# 将 fillchar 转换为与数组 a 相同的数据类型的 NumPy 数组
fillchar = np.asanyarray(fillchar, dtype=a.dtype)
# 如果 fillchar 中有任何一个元素的长度不等于 1,则抛出 TypeError 异常
if np.any(str_len(fillchar) != 1):
raise TypeError(
"The fill character must be exactly one character long")
# 如果数组 a 的数据类型是 'T'(字符串类型),则调用 _rjust 函数右对齐数组 a
if a.dtype.char == "T":
return _rjust(a, width, fillchar)
# 计算数组 a 和 width 的最大字符串长度
width = np.maximum(str_len(a), width)
# 计算广播后的形状,以适应 a 的形状、width 的形状和 fillchar 的形状
shape = np.broadcast_shapes(a.shape, width.shape, fillchar.shape)
# 根据计算得到的形状和数据类型创建一个与 a 相同类型的空数组 out
out_dtype = f"{a.dtype.char}{width.max()}"
out = np.empty_like(a, shape=shape, dtype=out_dtype)
# 调用 _rjust 函数,使用计算得到的数组 a、width 和 fillchar 进行右对齐操作,结果存入 out
return _rjust(a, width, fillchar, out=out)
# 定义一个函数 zfill,用于将数字字符串左侧填充零。如果有符号前缀(+/-),则在符号字符之后填充零。
def zfill(a, width):
"""
Return the numeric string left-filled with zeros. A leading
sign prefix (``+``/``-``) is handled by inserting the padding
after the sign character rather than before.
Parameters
----------
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
输入参数 `a`,可以是数组形式,数据类型可以是字符串、字节串或字符串数组
width : array_like, with any integer dtype
输入参数 `width`,可以是任意整数数据类型的数组,指定要填充到的字符串宽度
Returns
-------
out : ndarray
返回值是一个数组,数据类型为 `StringDType`、`bytes_` 或 `str_`,具体取决于输入类型
See Also
--------
str.zfill
Examples
--------
>>> np.strings.zfill(['1', '-1', '+1'], 3)
array(['001', '-01', '+01'], dtype='<U3')
"""
# 将输入参数 `a` 转换为任意数组
a = np.asanyarray(a)
# 如果输入数组 `a` 的数据类型字符为 "T",则调用内部函数 `_zfill` 处理
if a.dtype.char == "T":
return _zfill(a, width)
# 计算 `a` 中每个元素的字符串长度,并与 `width` 取最大值
width = np.maximum(str_len(a), width)
# 广播 `a` 和 `width` 的形状,得到输出数组的形状
shape = np.broadcast_shapes(a.shape, width.shape)
# 输出数组的数据类型,由 `a` 的数据类型字符和 `width` 最大值组成
out_dtype = f"{a.dtype.char}{width.max()}"
# 创建一个和 `a` 类型相同、形状为 `shape`、数据类型为 `out_dtype` 的空数组
out = np.empty_like(a, shape=shape, dtype=out_dtype)
# 调用内部函数 `_zfill` 处理并返回结果
return _zfill(a, width, out=out)
# 定义一个函数 lstrip,用于去除每个元素开头的指定字符集合
def lstrip(a, chars=None):
"""
For each element in `a`, return a copy with the leading characters
removed.
Parameters
----------
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
输入参数 `a`,可以是数组形式,数据类型可以是字符串、字节串或字符串数组
chars : scalar with the same dtype as ``a``, optional
The ``chars`` argument is a string specifying the set of
characters to be removed. If ``None``, the ``chars``
argument defaults to removing whitespace. The ``chars`` argument
is not a prefix or suffix; rather, all combinations of its
values are stripped.
Returns
-------
out : ndarray
返回值是一个数组,数据类型为 `StringDType`、`bytes_` 或 `str_`,具体取决于输入类型
See Also
--------
str.lstrip
Examples
--------
>>> c = np.array(['aAaAaA', ' aA ', 'abBABba'])
>>> c
array(['aAaAaA', ' aA ', 'abBABba'], dtype='<U7')
# The 'a' variable is unstripped from c[1] because of leading whitespace.
>>> np.strings.lstrip(c, 'a')
array(['AaAaA', ' aA ', 'bBABba'], dtype='<U7')
>>> np.strings.lstrip(c, 'A') # leaves c unchanged
array(['aAaAaA', ' aA ', 'abBABba'], dtype='<U7')
>>> (np.strings.lstrip(c, ' ') == np.strings.lstrip(c, '')).all()
np.False_
>>> (np.strings.lstrip(c, ' ') == np.strings.lstrip(c)).all()
np.True_
"""
# 如果 `chars` 参数为 `None`,则调用内部函数 `_lstrip_whitespace` 去除空白字符
if chars is None:
return _lstrip_whitespace(a)
# 否则调用内部函数 `_lstrip_chars` 去除指定的字符集合 `chars`
return _lstrip_chars(a, chars)
# 定义一个函数 rstrip,用于去除每个元素末尾的指定字符集合
def rstrip(a, chars=None):
"""
For each element in `a`, return a copy with the trailing characters
removed.
Parameters
----------
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
输入参数 `a`,可以是数组形式,数据类型可以是字符串、字节串或字符串数组
chars : scalar with the same dtype as ``a``, optional
The ``chars`` argument is a string specifying the set of
characters to be removed. If ``None``, the ``chars``
argument defaults to removing whitespace. The ``chars`` argument
is not a prefix or suffix; rather, all combinations of its
values are stripped.
Returns
-------
out : ndarray
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
depending on input types
See Also
--------
str.rstrip
Examples
--------
>>> c = np.array(['aAaAaA', 'abBABba'])
>>> c
array(['aAaAaA', 'abBABba'], dtype='<U7')
>>> np.strings.rstrip(c, 'a')
array(['aAaAaA', 'abBABb'], dtype='<U7')
>>> np.strings.rstrip(c, 'A')
array(['aAaAa', 'abBABba'], dtype='<U7')
"""
# 如果 chars 参数为 None,则调用 _rstrip_whitespace 函数去除字符串末尾的空白字符
if chars is None:
return _rstrip_whitespace(a)
# 否则,调用 _rstrip_chars 函数去除字符串末尾指定的字符集合
return _rstrip_chars(a, chars)
def strip(a, chars=None):
"""
For each element in `a`, return a copy with the leading and
trailing characters removed.
Parameters
----------
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
Input array.
chars : scalar with the same dtype as ``a``, optional
The ``chars`` argument is a string specifying the set of
characters to be removed. If ``None``, the ``chars``
argument defaults to removing whitespace. The ``chars`` argument
is not a prefix or suffix; rather, all combinations of its
values are stripped.
Returns
-------
out : ndarray
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
depending on input types
See Also
--------
str.strip
Examples
--------
>>> c = np.array(['aAaAaA', ' aA ', 'abBABba'])
>>> c
array(['aAaAaA', ' aA ', 'abBABba'], dtype='<U7')
>>> np.strings.strip(c)
array(['aAaAaA', 'aA', 'abBABba'], dtype='<U7')
# 'a' unstripped from c[1] because of leading whitespace.
>>> np.strings.strip(c, 'a')
array(['AaAaA', ' aA ', 'bBABb'], dtype='<U7')
# 'A' unstripped from c[1] because of trailing whitespace.
>>> np.strings.strip(c, 'A')
array(['aAaAa', ' aA ', 'abBABba'], dtype='<U7')
"""
# 如果 `chars` 参数为 None,则调用 _strip_whitespace 函数去除空白字符
if chars is None:
return _strip_whitespace(a)
# 否则,调用 _strip_chars 函数去除指定的字符集合
return _strip_chars(a, chars)
def upper(a):
"""
Return an array with the elements converted to uppercase.
Calls :meth:`str.upper` element-wise.
For 8-bit strings, this method is locale-dependent.
Parameters
----------
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
Input array.
Returns
-------
out : ndarray
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
depending on input types
See Also
--------
str.upper
Examples
--------
>>> c = np.array(['a1b c', '1bca', 'bca1']); c
array(['a1b c', '1bca', 'bca1'], dtype='<U5')
>>> np.strings.upper(c)
array(['A1B C', '1BCA', 'BCA1'], dtype='<U5')
"""
# 将输入数组 `a` 转换为 ndarray 类型
a_arr = np.asarray(a)
# 调用 _vec_string 函数,将元素逐个转换为大写形式
return _vec_string(a_arr, a_arr.dtype, 'upper')
def lower(a):
"""
Return an array with the elements converted to lowercase.
Call :meth:`str.lower` element-wise.
For 8-bit strings, this method is locale-dependent.
Parameters
----------
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
Input array.
Returns
-------
out : ndarray
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
depending on input types
See Also
--------
str.lower
Examples
--------
>>> c = np.array(['A1B C', '1BCA', 'BCA1']); c
array(['A1B C', '1BCA', 'BCA1'], dtype='<U5')
>>> np.strings.lower(c)
array(['a1b c', '1bca', 'bca1'], dtype='<U5')
"""
# 将输入数组 `a` 转换为 ndarray 类型
a_arr = np.asarray(a)
# 调用 _vec_string 函数,将元素逐个转换为小写形式
return _vec_string(a_arr, a_arr.dtype, 'lower')
def swapcase(a):
"""
Return an array with uppercase characters converted to lowercase
and vice versa.
Call :meth:`str.swapcase` element-wise.
Parameters
----------
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
Input array.
Returns
-------
out : ndarray
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
depending on input types
See Also
--------
str.swapcase
Examples
--------
>>> c = np.array(['aAaAaA', ' aA ', 'abBABba']); c
array(['aAaAaA', ' aA ', 'abBABba'], dtype='<U7')
>>> np.strings.swapcase(c)
array(['AaAaAa', ' Aa ', 'ABbabBA'], dtype='<U7')
"""
# 将输入数组 `a` 转换为 ndarray 类型
a_arr = np.asarray(a)
# 调用 _vec_string 函数,将大写转换为小写,小写转换为大写
return _vec_string(a_arr, a_arr.dtype, 'swapcase')
"""
将字符串中的大写字符转换为小写字符,小写字符转换为大写字符,并返回副本。
调用 :meth:`str.swapcase` 来实现逐元素转换。
对于8位字符串,此方法依赖于本地化设置。
Parameters
----------
a : array-like,具有 ``StringDType``, ``bytes_``, 或 ``str_`` 数据类型
输入数组。
Returns
-------
out : ndarray
输出数组,数据类型为 ``StringDType``, ``bytes_`` 或 ``str_``,取决于输入类型。
See Also
--------
str.swapcase
Examples
--------
>>> c=np.array(['a1B c','1b Ca','b Ca1','cA1b'],'S5'); c
array(['a1B c', '1b Ca', 'b Ca1', 'cA1b'],
dtype='|S5')
>>> np.strings.swapcase(c)
array(['A1b C', '1B cA', 'B cA1', 'Ca1B'],
dtype='|S5')
"""
# 将输入的数组转换为 numpy 数组
a_arr = np.asarray(a)
# 调用内部函数 _vec_string,传入输入数组、数组的数据类型和操作类型 'swapcase',返回处理后的数组
return _vec_string(a_arr, a_arr.dtype, 'swapcase')
def capitalize(a):
"""
Return a copy of ``a`` with only the first character of each element
capitalized.
Calls :meth:`str.capitalize` element-wise.
For byte strings, this method is locale-dependent.
Parameters
----------
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
Input array of strings to capitalize.
Returns
-------
out : ndarray
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
depending on input types
See Also
--------
str.capitalize
Examples
--------
>>> c = np.array(['a1b2','1b2a','b2a1','2a1b'],'S4'); c
array(['a1b2', '1b2a', 'b2a1', '2a1b'],
dtype='|S4')
>>> np.strings.capitalize(c)
array(['A1b2', '1b2a', 'B2a1', '2a1b'],
dtype='|S4')
"""
# 将输入数组转换为 NumPy 数组
a_arr = np.asarray(a)
# 调用内部函数 _vec_string 进行字符串首字母大写处理
return _vec_string(a_arr, a_arr.dtype, 'capitalize')
def title(a):
"""
Return element-wise title cased version of string or unicode.
Title case words start with uppercase characters, all remaining cased
characters are lowercase.
Calls :meth:`str.title` element-wise.
For 8-bit strings, this method is locale-dependent.
Parameters
----------
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
Input array.
Returns
-------
out : ndarray
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
depending on input types
See Also
--------
str.title
Examples
--------
>>> c=np.array(['a1b c','1b ca','b ca1','ca1b'],'S5'); c
array(['a1b c', '1b ca', 'b ca1', 'ca1b'],
dtype='|S5')
>>> np.strings.title(c)
array(['A1B C', '1B Ca', 'B Ca1', 'Ca1B'],
dtype='|S5')
"""
# 将输入数组转换为 NumPy 数组
a_arr = np.asarray(a)
# 调用内部函数 _vec_string 进行字符串标题格式处理
return _vec_string(a_arr, a_arr.dtype, 'title')
def replace(a, old, new, count=-1):
"""
For each element in ``a``, return a copy of the string with
occurrences of substring ``old`` replaced by ``new``.
Parameters
----------
a : array_like, with ``bytes_`` or ``str_`` dtype
old, new : array_like, with ``bytes_`` or ``str_`` dtype
count : array_like, with ``int_`` dtype
If the optional argument ``count`` is given, only the first
``count`` occurrences are replaced.
Returns
-------
out : ndarray
Output array of ``StringDType``, ``bytes_`` or ``str_`` dtype,
depending on input types
See Also
--------
str.replace
Examples
--------
>>> a = np.array(["That is a mango", "Monkeys eat mangos"])
>>> np.strings.replace(a, 'mango', 'banana')
array(['That is a banana', 'Monkeys eat bananas'], dtype='<U19')
>>> a = np.array(["The dish is fresh", "This is it"])
>>> np.strings.replace(a, 'is', 'was')
array(['The dwash was fresh', 'Thwas was it'], dtype='<U19')
"""
# 将输入数组转换为 NumPy 通用数组
arr = np.asanyarray(a)
# 获取数组的数据类型
a_dt = arr.dtype
# 将旧数组转换为NumPy数组,如果没有指定dtype,则使用a_dt
old = np.asanyarray(old, dtype=getattr(old, 'dtype', a_dt))
# 将新数组转换为NumPy数组,如果没有指定dtype,则使用a_dt
new = np.asanyarray(new, dtype=getattr(new, 'dtype', a_dt))
# 将count转换为NumPy数组
count = np.asanyarray(count)
# 如果数组arr的dtype的字符代码为"T"(代表'timedelta'类型),则调用_replace函数进行替换操作并返回结果
if arr.dtype.char == "T":
return _replace(arr, old, new, count)
# 获取np.int64类型的最大值
max_int64 = np.iinfo(np.int64).max
# 调用_count_ufunc函数计算在数组arr中与old匹配的元素数量,限制计数不超过max_int64
counts = _count_ufunc(arr, old, 0, max_int64)
# 根据count数组的值对counts数组进行调整:如果count小于0,则保留原有counts值;否则取counts和count中较小的值
counts = np.where(count < 0, counts, np.minimum(counts, count))
# 根据替换操作计算输出数组的缓冲区大小,buffersizes的每个元素表示对应位置的替换后字符串的长度变化
buffersizes = str_len(arr) + counts * (str_len(new) - str_len(old))
# 构建输出数组的dtype,字符代码为原始arr的dtype的字符代码,并根据buffersizes的最大值确定dtype的长度
out_dtype = f"{arr.dtype.char}{buffersizes.max()}"
# 根据out_dtype创建一个与arr形状相同且dtype为out_dtype的空数组out
out = np.empty_like(arr, shape=buffersizes.shape, dtype=out_dtype)
# 调用_replace函数,使用old、new和counts替换arr中的元素,并将结果存入out数组中
return _replace(arr, old, new, counts, out=out)
# 返回一个字符串,该字符串是序列 `seq` 中字符串连接而成的结果。
# 对每个元素调用 :meth:`str.join` 方法进行连接。
def _join(sep, seq):
# 调用 _vec_string 函数,将 sep 和 seq 转换为字节或字符串数组,然后进行连接操作
return _to_bytes_or_str_array(
_vec_string(sep, np.object_, 'join', (seq,)), seq)
# 对于每个元素 `a`,使用 `sep` 作为分隔符字符串,返回字符串中的单词列表。
# 对每个元素调用 :meth:`str.split` 方法进行分割。
def _split(a, sep=None, maxsplit=None):
# 这将返回一个大小不同的列表数组,因此我们将其保留为对象数组
return _vec_string(
a, np.object_, 'split', [sep] + _clean_args(maxsplit))
# 对于每个元素 `a`,使用 `sep` 作为分隔符字符串,从右向左返回字符串中的单词列表。
# 对每个元素调用 :meth:`str.rsplit` 方法进行分割。
# 与 `split` 类似,不同之处在于从右侧开始分割。
def _rsplit(a, sep=None, maxsplit=None):
return _vec_string(
a, np.object_, 'rsplit', [sep] + _clean_args(maxsplit))
这些函数是针对 NumPy 数组中包含的字符串元素进行操作的工具函数,使用了 NumPy 的字符串处理功能。
"""
# 返回一个数组,其中包含不同大小的列表,因此我们将其保留为对象数组
# 这个数组可能包含不同长度的列表,因此数据类型被指定为对象数组
return _vec_string(
a, np.object_, 'rsplit', [sep] + _clean_args(maxsplit))
"""
def _splitlines(a, keepends=None):
"""
对 `a` 中的每个元素进行操作,返回每个元素按行划分后的列表。
调用 :meth:`str.splitlines` 方法逐个元素处理。
Parameters
----------
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
输入数组,元素类型为字符串或字节流
keepends : bool, optional
如果为 True,则结果列表中保留行结束符;默认情况下不包含行结束符。
Returns
-------
out : ndarray
包含列表对象的数组
See Also
--------
str.splitlines
"""
# 调用 `_vec_string` 函数对每个元素进行 `splitlines` 操作,传递 `keepends` 参数
return _vec_string(
a, np.object_, 'splitlines', _clean_args(keepends))
def partition(a, sep):
"""
对 `a` 中的每个元素围绕 `sep` 进行分区。
对 `a` 中的每个元素,在第一次出现 `sep` 的位置进行分割,并返回一个三元组,
包含分隔符之前的部分、分隔符本身和分隔符之后的部分。如果找不到分隔符,
则三元组的第一项将包含整个字符串,第二和第三项将为空字符串。
Parameters
----------
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
输入数组
sep : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
用于分割每个字符串元素的分隔符。
Returns
-------
out : 3-tuple:
- 元素类型为 ``StringDType``, ``bytes_`` 或 ``str_`` 的数组,包含分隔符之前的部分
- 元素类型为 ``StringDType``, ``bytes_`` 或 ``str_`` 的数组,包含分隔符本身
- 元素类型为 ``StringDType``, ``bytes_`` 或 ``str_`` 的数组,包含分隔符之后的部分
See Also
--------
str.partition
Examples
--------
>>> x = np.array(["Numpy is nice!"])
>>> np.strings.partition(x, " ")
(array(['Numpy'], dtype='<U5'),
array([' '], dtype='<U1'),
array(['is nice!'], dtype='<U8'))
"""
# 将 `a` 转换为 `ndarray`
a = np.asanyarray(a)
# 当问题围绕视图问题解决时,切换到 copy=False
sep = np.array(sep, dtype=a.dtype, copy=True, subok=True)
if a.dtype.char == "T":
return _partition(a, sep)
# 在 `a` 中寻找 `sep` 的位置
pos = _find_ufunc(a, sep, 0, MAX)
a_len = str_len(a)
sep_len = str_len(sep)
not_found = pos < 0
buffersizes1 = np.where(not_found, a_len, pos)
buffersizes3 = np.where(not_found, 0, a_len - pos - sep_len)
# 计算输出的 dtype
out_dtype = ",".join([f"{a.dtype.char}{n}" for n in (
buffersizes1.max(),
1 if np.all(not_found) else sep_len.max(),
buffersizes3.max(),
)])
shape = np.broadcast_shapes(a.shape, sep.shape)
# 创建输出数组
out = np.empty_like(a, shape=shape, dtype=out_dtype)
return _partition_index(a, sep, pos, out=(out["f0"], out["f1"], out["f2"]))
occurrence of ``sep``, and return a 3-tuple containing the part
before the separator, the separator itself, and the part after
the separator. If the separator is not found, the third item of
the tuple will contain the whole string, and the first and second
ones will be the empty string.
Parameters
----------
a : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
Input array
sep : array-like, with ``StringDType``, ``bytes_``, or ``str_`` dtype
Separator to split each string element in ``a``.
Returns
-------
out : 3-tuple:
- array with ``StringDType``, ``bytes_`` or ``str_`` dtype with the
part before the separator
- array with ``StringDType``, ``bytes_`` or ``str_`` dtype with the
separator
- array with ``StringDType``, ``bytes_`` or ``str_`` dtype with the
part after the separator
See Also
--------
str.rpartition
Examples
--------
>>> a = np.array(['aAaAaA', ' aA ', 'abBABba'])
>>> np.strings.rpartition(a, 'A')
(array(['aAaAa', ' a', 'abB'], dtype='<U5'),
array(['A', 'A', 'A'], dtype='<U1'),
array(['', ' ', 'Bba'], dtype='<U3'))
"""
# 将输入的数组 a 转换为 NumPy 数组
a = np.asanyarray(a)
# TODO switch to copy=False when issues around views are fixed
# 将分隔符数组 sep 转换为与 a 相同类型的 NumPy 数组副本
sep = np.array(sep, dtype=a.dtype, copy=True, subok=True)
# 如果 a 的数据类型是 'T',调用 _rpartition 函数处理
if a.dtype.char == "T":
return _rpartition(a, sep)
# 使用 _rfind_ufunc 函数查找 sep 在 a 中最后出现的位置
pos = _rfind_ufunc(a, sep, 0, MAX)
# 计算 a 和 sep 的长度
a_len = str_len(a)
sep_len = str_len(sep)
# 判断是否找到分隔符,如果没找到则设置相应的缓冲区大小为 0 或者 a 和 sep 的长度
not_found = pos < 0
buffersizes1 = np.where(not_found, 0, pos)
buffersizes3 = np.where(not_found, a_len, a_len - pos - sep_len)
# 构建输出的数据类型,包括部分之前的长度、分隔符长度和部分之后的长度
out_dtype = ",".join([f"{a.dtype.char}{n}" for n in (
buffersizes1.max(),
1 if np.all(not_found) else sep_len.max(),
buffersizes3.max(),
)])
# 广播输入数组 a 和 sep 的形状
shape = np.broadcast_shapes(a.shape, sep.shape)
# 创建一个与 a 类型相同的空数组作为输出
out = np.empty_like(a, shape=shape, dtype=out_dtype)
# 调用 _rpartition_index 函数进行分区操作,将结果存储在 out 中的对应字段
return _rpartition_index(
a, sep, pos, out=(out["f0"], out["f1"], out["f2"]))
def translate(a, table, deletechars=None):
"""
对于 `a` 中的每个元素,返回一个新字符串副本,其中删除了在可选参数 `deletechars` 中出现的所有字符,并将剩余字符通过给定的转换表映射。
逐元素调用 :meth:`str.translate`。
Parameters
----------
a : array-like, with `np.bytes_` or `np.str_` dtype
输入数组,元素类型为 `np.bytes_` 或 `np.str_`
table : str of length 256
长度为 256 的字符串转换表
deletechars : str, optional
要删除的字符集合,可选参数
Returns
-------
out : ndarray
输出的字符串数组,根据输入类型为 str 或 unicode
See Also
--------
str.translate
Examples
--------
>>> a = np.array(['a1b c', '1bca', 'bca1'])
>>> table = a[0].maketrans('abc', '123')
>>> deletechars = ' '
>>> np.char.translate(a, table, deletechars)
array(['112 3', '1231', '2311'], dtype='<U5')
"""
# 将输入 `a` 转换为 ndarray 类型
a_arr = np.asarray(a)
# 如果 `a_arr` 的元素类型是字符串类型
if issubclass(a_arr.dtype.type, np.str_):
# 调用 _vec_string 函数处理字符串类型的数组 `a_arr`,并返回结果
return _vec_string(
a_arr, a_arr.dtype, 'translate', (table,))
else:
# 否则,调用 _vec_string 函数处理非字符串类型的数组 `a_arr`,并返回结果
return _vec_string(
a_arr,
a_arr.dtype,
'translate',
[table] + _clean_args(deletechars)
)
.\numpy\numpy\_core\strings.pyi
from typing import Any, overload
import numpy as np
from numpy._typing import (
NDArray,
_ArrayLikeStr_co as U_co,
_ArrayLikeBytes_co as S_co,
_ArrayLikeInt_co as i_co,
_ArrayLikeBool_co as b_co,
)
@overload
def equal(x1: U_co, x2: U_co) -> NDArray[np.bool]: ...
@overload
def equal(x1: S_co, x2: S_co) -> NDArray[np.bool]: ...
@overload
def not_equal(x1: U_co, x2: U_co) -> NDArray[np.bool]: ...
@overload
def not_equal(x1: S_co, x2: S_co) -> NDArray[np.bool]: ...
@overload
def greater_equal(x1: U_co, x2: U_co) -> NDArray[np.bool]: ...
@overload
def greater_equal(x1: S_co, x2: S_co) -> NDArray[np.bool]: ...
@overload
def less_equal(x1: U_co, x2: U_co) -> NDArray[np.bool]: ...
@overload
def less_equal(x1: S_co, x2: S_co) -> NDArray[np.bool]: ...
@overload
def greater(x1: U_co, x2: U_co) -> NDArray[np.bool]: ...
@overload
def greater(x1: S_co, x2: S_co) -> NDArray[np.bool]: ...
@overload
def less(x1: U_co, x2: U_co) -> NDArray[np.bool]: ...
@overload
def less(x1: S_co, x2: S_co) -> NDArray[np.bool]: ...
@overload
def add(x1: U_co, x2: U_co) -> NDArray[np.str_]: ...
@overload
def add(x1: S_co, x2: S_co) -> NDArray[np.bytes_]: ...
@overload
def multiply(a: U_co, i: i_co) -> NDArray[np.str_]: ...
@overload
def multiply(a: S_co, i: i_co) -> NDArray[np.bytes_]: ...
@overload
def mod(a: U_co, value: Any) -> NDArray[np.str_]: ...
@overload
def mod(a: S_co, value: Any) -> NDArray[np.bytes_]: ...
def isalpha(x: U_co | S_co) -> NDArray[np.bool]: ...
def isalnum(a: U_co | S_co) -> NDArray[np.bool]: ...
def isdigit(x: U_co | S_co) -> NDArray[np.bool]: ...
def isspace(x: U_co | S_co) -> NDArray[np.bool]: ...
def isdecimal(x: U_co) -> NDArray[np.bool]: ...
def isnumeric(x: U_co) -> NDArray[np.bool]: ...
def islower(a: U_co | S_co) -> NDArray[np.bool]: ...
def istitle(a: U_co | S_co) -> NDArray[np.bool]: ...
def isupper(a: U_co | S_co) -> NDArray[np.bool]: ...
def str_len(x: U_co | S_co) -> NDArray[np.int_]: ...
@overload
def find(
a: U_co,
sub: U_co,
start: i_co = ...,
end: i_co | None = ...,
) -> NDArray[np.int_]: ...
@overload
def find(
a: S_co,
sub: S_co,
start: i_co = ...,
end: i_co | None = ...,
) -> NDArray[np.int_]: ...
@overload
def rfind(
a: U_co,
sub: U_co,
start: i_co = ...,
end: i_co | None = ...,
) -> NDArray[np.int_]: ...
@overload
def rfind(
a: S_co,
sub: S_co,
start: i_co = ...,
end: i_co | None = ...,
) -> NDArray[np.int_]: ...
@overload
def index(
a: U_co,
sub: U_co,
start: i_co = ...,
end: None | i_co = ...,
) -> NDArray[np.int_]: ...
@overload
def index(
a: S_co,
sub: S_co,
start: i_co = ...,
end: None | i_co = ...,
) -> NDArray[np.int_]: ...
@overload
def rindex(
a: U_co,
sub: U_co,
start: i_co = ...,
end: None | i_co = ...,
) -> NDArray[np.int_]: ...
@overload
def rindex(
a: S_co,
sub: S_co,
start: i_co = ...,
end: None | i_co = ...,
) -> NDArray[np.int_]: ...
@overload
def count(
a: U_co,
sub: U_co,
start: i_co = ...,
end: i_co | None = ...,
) -> NDArray[np.int_]: ...
@overload
def count(
a: S_co,
sub: S_co,
start: i_co = ...,
end: i_co | None = ...,
) -> NDArray[np.int_]: ...
@overload
def startswith(
a: U_co,
prefix: U_co,
start: i_co = ...,
end: i_co | None = ...,
) -> NDArray[np.bool]: ...
@overload
def endswith(
a: U_co,
suffix: U_co,
start: i_co = ...,
end: i_co | None = ...,
) -> NDArray[np.bool]: ...
def decode(
a: S_co,
encoding: None | str = ...,
errors: None | str = ...,
) -> NDArray[np.str_]: ...
def encode(
a: U_co,
encoding: None | str = ...,
errors: None | str = ...,
) -> NDArray[np.bytes_]: ...
@overload
def expandtabs(a: U_co, tabsize: i_co = ...) -> NDArray[np.str_]: ...
@overload
def expandtabs(a: S_co, tabsize: i_co = ...) -> NDArray[np.bytes_]: ...
@overload
def center(a: U_co, width: i_co, fillchar: U_co = ...) -> NDArray[np.str_]: ...
@overload
def center(a: S_co, width: i_co, fillchar: S_co = ...) -> NDArray[np.bytes_]: ...
@overload
def ljust(a: U_co, width: i_co, fillchar: U_co = ...) -> NDArray[np.str_]: ...
@overload
def ljust(a: S_co, width: i_co, fillchar: S_co = ...) -> NDArray[np.bytes_]: ...
@overload
def rjust(
a: U_co,
width: i_co,
fillchar: U_co = ...,
) -> NDArray[np.str_]: ...
@overload
def rjust(
a: S_co,
width: i_co,
fillchar: S_co = ...,
) -> NDArray[np.bytes_]: ...
@overload
def lstrip(a: U_co, chars: None | U_co = ...) -> NDArray[np.str_]: ...
@overload
def lstrip(a: S_co, chars: None | S_co = ...) -> NDArray[np.bytes_]: ...
@overload
def rstrip(a: U_co, char: None | U_co = ...) -> NDArray[np.str_]: ...
@overload
def rstrip(a: S_co, char: None | S_co = ...) -> NDArray[np.bytes_]: ...
@overload
def strip(a: U_co, chars: None | U_co = ...) -> NDArray[np.str_]: ...
@overload
def strip(a: S_co, chars: None | S_co = ...) -> NDArray[np.bytes_]: ...
@overload
def zfill(a: U_co, width: i_co) -> NDArray[np.str_]: ...
@overload
def zfill(a: S_co, width: i_co) -> NDArray[np.bytes_]: ...
@overload
def upper(a: U_co) -> NDArray[np.str_]: ...
@overload
def upper(a: S_co) -> NDArray[np.bytes_]: ...
@overload
def lower(a: U_co) -> NDArray[np.str_]: ...
@overload
def lower(a: S_co) -> NDArray[np.bytes_]: ...
@overload
def swapcase(a: U_co) -> NDArray[np.str_]: ...
@overload
def swapcase(a: S_co) -> NDArray[np.bytes_]: ...
@overload
def capitalize(a: U_co) -> NDArray[np.str_]: ...
@overload
def capitalize(a: S_co) -> NDArray[np.bytes_]: ...
@overload
def title(a: U_co) -> NDArray[np.str_]: ...
@overload
def title(a: S_co) -> NDArray[np.bytes_]: ...
def replace(
a: U_co,
old: U_co,
new: U_co,
count: i_co = ...,
) -> NDArray[np.str_]: ...
def replace(
a: S_co,
old: S_co,
new: S_co,
count: i_co = ...,
) -> NDArray[np.bytes_]: ...
@overload
def join(sep: U_co, seq: U_co) -> NDArray[np.str_]: ...
@overload
def join(sep: S_co, seq: S_co) -> NDArray[np.bytes_]: ...
@overload
def split(
a: U_co,
sep: None | U_co = ...,
maxsplit: None | i_co = ...,
) -> NDArray[np.object_]: ...
@overload
def split(
a: S_co,
sep: None | S_co = ...,
maxsplit: None | i_co = ...,
) -> NDArray[np.object_]: ...
@overload
def rsplit(
a: U_co,
sep: None | U_co = ...,
maxsplit: None | i_co = ...,
) -> NDArray[np.object_]: ...
@overload
def rsplit(
a: S_co,
sep: None | S_co = ...,
maxsplit: None | i_co = ...,
) -> NDArray[np.object_]: ...
@overload
def splitlines(a: U_co, keepends: None | b_co = ...) -> NDArray[np.object_]: ...
@overload
def splitlines(a: S_co, keepends: None | b_co = ...) -> NDArray[np.object_]: ...
@overload
def partition(a: U_co, sep: U_co) -> NDArray[np.str_]: ...
@overload
def partition(a: S_co, sep: S_co) -> NDArray[np.bytes_]: ...
@overload
def rpartition(a: U_co, sep: U_co) -> NDArray[np.str_]: ...
@overload
def rpartition(a: S_co, sep: S_co) -> NDArray[np.bytes_]: ...
@overload
def translate(
a: U_co,
table: U_co,
deletechars: None | U_co = ...,
) -> NDArray[np.str_]: ...
@overload
def translate(
a: S_co,
table: S_co,
deletechars: None | S_co = ...,
) -> NDArray[np.bytes_]: ...
.\numpy\numpy\_core\tests\data\generate_umath_validation_data.cpp
/*
* 包含标准库头文件
*/
/*
* 定义结构体ufunc,用于存储数学函数信息
*/
struct ufunc {
std::string name; // 函数名称
double (*f32func)(double); // 双精度浮点函数指针
long double (*f64func)(long double);// 长双精度浮点函数指针
float f32ulp; // 单精度浮点误差限
float f64ulp; // 双精度浮点误差限
};
/*
* 模板函数RandomFloat,生成指定范围[a, b)内的随机浮点数
*/
template <typename T>
T
RandomFloat(T a, T b)
{
T random = ((T)rand()) / (T)RAND_MAX; // 生成0到1之间的随机数
T diff = b - a; // 计算范围差值
T r = random * diff; // 缩放随机数到指定范围
return a + r; // 返回随机数
}
/*
* 模板函数append_random_array,向向量arr中添加N个指定范围[min, max)内的随机数
*/
template <typename T>
void
append_random_array(std::vector<T> &arr, T min, T max, size_t N)
{
for (size_t ii = 0; ii < N; ++ii)
arr.emplace_back(RandomFloat<T>(min, max)); // 调用RandomFloat生成随机数并添加到向量中
}
/*
* 模板函数computeTrueVal,计算输入向量in中每个元素应用数学函数mathfunc后的结果,并返回结果向量
*/
template <typename T1, typename T2>
std::vector<T1>
computeTrueVal(const std::vector<T1> &in, T2 (*mathfunc)(T2))
{
std::vector<T1> out; // 定义输出向量
for (T1 elem : in) { // 遍历输入向量中的每个元素
T2 elem_d = (T2)elem; // 将元素转换为T2类型
T1 out_elem = (T1)mathfunc(elem_d); // 计算元素经过mathfunc函数后的结果
out.emplace_back(out_elem); // 将结果添加到输出向量中
}
return out; // 返回结果向量
}
/*
* FP range:
* [-inf, -maxflt, -1., -minflt, -minden, 0., minden, minflt, 1., maxflt, inf]
*/
/*
* 定义各种特殊浮点数常量的宏
*/
/*
* 模板函数generate_input_vector,根据函数名称func生成对应的输入向量
*/
template <typename T>
std::vector<T>
generate_input_vector(std::string func)
{
std::vector<T> input = {MINDEN, -MINDEN, MINFLT, -MINFLT, MAXFLT,
-MAXFLT, INF, -INF, qNAN, sNAN,
-1.0, 1.0, 0.0, -0.0}; // 初始化输入向量
// 根据函数名称func生成不同范围的随机数并添加到输入向量中
// [-1.0, 1.0]
if ((func == "arcsin") || (func == "arccos") || (func == "arctanh")) {
append_random_array<T>(input, -1.0, 1.0, 700);
}
// (0.0, INF]
else if ((func == "log2") || (func == "log10")) {
append_random_array<T>(input, 0.0, 1.0, 200);
append_random_array<T>(input, MINDEN, MINFLT, 200);
append_random_array<T>(input, MINFLT, 1.0, 200);
append_random_array<T>(input, 1.0, MAXFLT, 200);
}
// (-1.0, INF]
else if (func == "log1p") {
append_random_array<T>(input, -1.0, 1.0, 200);
append_random_array<T>(input, -MINFLT, -MINDEN, 100);
append_random_array<T>(input, -1.0, -MINFLT, 100);
append_random_array<T>(input, MINDEN, MINFLT, 100);
append_random_array<T>(input, MINFLT, 1.0, 100);
append_random_array<T>(input, 1.0, MAXFLT, 100);
}
// [1.0, INF]
else if (func == "arccosh") {
append_random_array<T>(input, 1.0, 2.0, 400);
append_random_array<T>(input, 2.0, MAXFLT, 300);
}
// [-INF, INF]
// 否则分支:在 input 后追加不同范围的随机数组成分
append_random_array<T>(input, -1.0, 1.0, 100);
append_random_array<T>(input, MINDEN, MINFLT, 100);
append_random_array<T>(input, -MINFLT, -MINDEN, 100);
append_random_array<T>(input, MINFLT, 1.0, 100);
append_random_array<T>(input, -1.0, -MINFLT, 100);
append_random_array<T>(input, 1.0, MAXFLT, 100);
append_random_array<T>(input, -MAXFLT, -100.0, 100);
// 对 input 中的元素进行随机重排
std::random_shuffle(input.begin(), input.end());
// 返回重排后的 input 数组
return input;
}
.\numpy\numpy\_core\tests\examples\cython\checks.pyx
"""
Functions in this module give python-space wrappers for cython functions
exposed in numpy/__init__.pxd, so they can be tested in test_cython.py
"""
cimport numpy as cnp
cnp.import_array()
def is_td64(obj):
return cnp.is_timedelta64_object(obj)
def is_dt64(obj):
return cnp.is_datetime64_object(obj)
def get_dt64_value(obj):
return cnp.get_datetime64_value(obj)
def get_td64_value(obj):
return cnp.get_timedelta64_value(obj)
def get_dt64_unit(obj):
return cnp.get_datetime64_unit(obj)
def is_integer(obj):
return isinstance(obj, (cnp.integer, int))
def get_datetime_iso_8601_strlen():
return cnp.get_datetime_iso_8601_strlen(0, cnp.NPY_FR_ns)
def convert_datetime64_to_datetimestruct():
cdef:
cnp.npy_datetimestruct dts
cnp.PyArray_DatetimeMetaData meta
cnp.int64_t value = 1647374515260292
meta.base = cnp.NPY_FR_us
meta.num = 1
cnp.convert_datetime64_to_datetimestruct(&meta, value, &dts)
return dts
def make_iso_8601_datetime(dt: "datetime"):
cdef:
cnp.npy_datetimestruct dts
char result[36]
dts.year = dt.year
dts.month = dt.month
dts.day = dt.day
dts.hour = dt.hour
dts.min = dt.minute
dts.sec = dt.second
dts.us = dt.microsecond
dts.ps = dts.as = 0
cnp.make_iso_8601_datetime(
&dts,
result,
sizeof(result),
0,
0,
cnp.NPY_FR_s,
0,
cnp.NPY_NO_CASTING,
)
return result
cdef cnp.broadcast multiiter_from_broadcast_obj(object bcast):
cdef dict iter_map = {
1: cnp.PyArray_MultiIterNew1,
2: cnp.PyArray_MultiIterNew2,
3: cnp.PyArray_MultiIterNew3,
4: cnp.PyArray_MultiIterNew4,
5: cnp.PyArray_MultiIterNew5,
}
arrays = [x.base for x in bcast.iters]
cdef cnp.broadcast result = iter_map[len(arrays)](*arrays)
return result
def get_multiiter_size(bcast: "broadcast"):
cdef cnp.broadcast multi = multiiter_from_broadcast_obj(bcast)
return multi.size
def get_multiiter_number_of_dims(bcast: "broadcast"):
cdef cnp.broadcast multi = multiiter_from_broadcast_obj(bcast)
return multi.nd
def get_multiiter_current_index(bcast: "broadcast"):
cdef cnp.broadcast multi = multiiter_from_broadcast_obj(bcast)
return multi.index
def get_multiiter_num_of_iterators(bcast: "broadcast"):
cdef cnp.broadcast multi = multiiter_from_broadcast_obj(bcast)
return multi.numiter
def get_multiiter_shape(bcast: "broadcast"):
cdef cnp.broadcast multi = multiiter_from_broadcast_obj(bcast)
return tuple([multi.dimensions[i] for i in range(bcast.nd)])
def get_multiiter_iters(bcast: "broadcast"):
cdef cnp.broadcast multi = multiiter_from_broadcast_obj(bcast)
return tuple([<cnp.flatiter>multi.iters[i] for i in range(bcast.numiter)])
def get_default_integer():
if cnp.NPY_DEFAULT_INT == cnp.NPY_LONG:
return cnp.dtype("long")
if cnp.NPY_DEFAULT_INT == cnp.NPY_INTP:
return cnp.dtype("intp")
return None
def conv_intp(cnp.intp_t val):
return val
def get_dtype_flags(cnp.dtype dtype):
return dtype.flags
cdef cnp.NpyIter* npyiter_from_nditer_obj(object it):
"""A function to create a NpyIter struct from a nditer object.
This function is only meant for testing purposes and only extracts the
necessary info from nditer to test the functionality of NpyIter methods
"""
cdef:
cnp.NpyIter* cit
cnp.PyArray_Descr* op_dtypes[3]
cnp.npy_uint32 op_flags[3]
cnp.PyArrayObject* ops[3]
cnp.npy_uint32 flags = 0
if it.has_index:
flags |= cnp.NPY_ITER_C_INDEX
if it.has_delayed_bufalloc:
flags |= cnp.NPY_ITER_BUFFERED | cnp.NPY_ITER_DELAY_BUFALLOC
if it.has_multi_index:
flags |= cnp.NPY_ITER_MULTI_INDEX
for i in range(it.nop):
op_flags[i] = cnp.NPY_ITER_READONLY
for i in range(it.nop):
op_dtypes[i] = cnp.PyArray_DESCR(it.operands[i])
ops[i] = <cnp.PyArrayObject*>it.operands[i]
cit = cnp.NpyIter_MultiNew(it.nop, &ops[0], flags, cnp.NPY_KEEPORDER,
cnp.NPY_NO_CASTING, &op_flags[0],
<cnp.PyArray_Descr**>NULL)
return cit
def get_npyiter_size(it: "nditer"):
cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it)
result = cnp.NpyIter_GetIterSize(cit)
cnp.NpyIter_Deallocate(cit)
return result
def get_npyiter_ndim(it: "nditer"):
cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it)
result = cnp.NpyIter_GetNDim(cit)
cnp.NpyIter_Deallocate(cit)
return result
def get_npyiter_nop(it: "nditer"):
cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it)
result = cnp.NpyIter_GetNOp(cit)
cnp.NpyIter_Deallocate(cit)
return result
def get_npyiter_operands(it: "nditer"):
cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it)
try:
arr = cnp.NpyIter_GetOperandArray(cit)
return tuple([<cnp.ndarray>arr[i] for i in range(it.nop)])
finally:
cnp.NpyIter_Deallocate(cit)
def get_npyiter_itviews(it: "nditer"):
cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it)
result = tuple([cnp.NpyIter_GetIterView(cit, i) for i in range(it.nop)])
cnp.NpyIter_Deallocate(cit)
return result
def get_npyiter_dtypes(it: "nditer"):
cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it)
try:
arr = cnp.NpyIter_GetDescrArray(cit)
return tuple([<cnp.dtype>arr[i] for i in range(it.nop)])
finally:
cnp.NpyIter_Deallocate(cit)
def npyiter_has_delayed_bufalloc(it: "nditer"):
cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it)
result = cnp.NpyIter_HasDelayedBufAlloc(cit)
cnp.NpyIter_Deallocate(cit)
return result
def npyiter_has_index(it: "nditer"):
cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it)
result = cnp.NpyIter_HasIndex(cit)
cnp.NpyIter_Deallocate(cit)
return result
def npyiter_has_multi_index(it: "nditer"):
cdef cnp.NpyIter* cit = npyiter_from_nditer_obj(it)
result = cnp.NpyIter_HasMultiIndex(cit)
cnp.NpyIter_Deallocate(cit)
return result
def npyiter_has_finished(it: "nditer"):
cdef cnp.NpyIter* cit
try:
cit = npyiter_from_nditer_obj(it)
cnp.NpyIter_GotoIterIndex(cit, it.index)
return not (cnp.NpyIter_GetIterIndex(cit) < cnp.NpyIter_GetIterSize(cit))
finally:
cnp.NpyIter_Deallocate(cit)
def compile_fillwithbyte():
cdef cnp.npy_intp dims[2]
dims = (1, 2)
pos = cnp.PyArray_ZEROS(2, dims, cnp.NPY_UINT8, 0)
cnp.PyArray_FILLWBYTE(pos, 1)
return pos
def inc2_cfloat_struct(cnp.ndarray[cnp.cfloat_t] arr):
arr[1].real += 1
arr[1].imag += 1
arr[1].real = arr[1].real + 1
arr[1].imag = arr[1].imag + 1
.\numpy\numpy\_core\tests\examples\cython\setup.py
"""
Provide python-space access to the functions exposed in numpy/__init__.pxd
for testing.
"""
import numpy as np
from distutils.core import setup
from Cython.Build import cythonize
from setuptools.extension import Extension
import os
macros = [
("NPY_NO_DEPRECATED_API", 0),
("NPY_TARGET_VERSION", "NPY_2_0_API_VERSION"),
]
checks = Extension(
"checks",
sources=[os.path.join('.', "checks.pyx")],
include_dirs=[np.get_include()],
define_macros=macros,
)
extensions = [checks]
setup(
ext_modules=cythonize(extensions)
)
.\numpy\numpy\_core\tests\examples\limited_api\limited_api1.c
static PyModuleDef moduledef = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "limited_api1"
};
PyMODINIT_FUNC PyInit_limited_api1(void)
{
import_array();
import_umath();
return PyModule_Create(&moduledef);
}
.\numpy\numpy\_core\tests\examples\limited_api\limited_api2.pyx
"""
Make sure cython can compile in limited API mode (see meson.build)
"""
cdef extern from "numpy/arrayobject.h":
pass
cdef extern from "numpy/arrayscalars.h":
pass
.\numpy\numpy\_core\tests\examples\limited_api\setup.py
"""
Build an example package using the limited Python C API.
"""
import numpy as np
from setuptools import setup, Extension
import os
macros = [("NPY_NO_DEPRECATED_API", 0), ("Py_LIMITED_API", "0x03060000")]
limited_api = Extension(
"limited_api",
sources=[os.path.join('.', "limited_api.c")],
include_dirs=[np.get_include()],
define_macros=macros,
)
extensions = [limited_api]
setup(
ext_modules=extensions
)
.\numpy\numpy\_core\tests\test_abc.py
from numpy.testing import assert_
import numbers
import numpy as np
from numpy._core.numerictypes import sctypes
class TestABC:
def test_abstract(self):
assert_(issubclass(np.number, numbers.Number))
assert_(issubclass(np.inexact, numbers.Complex))
assert_(issubclass(np.complexfloating, numbers.Complex))
assert_(issubclass(np.floating, numbers.Real))
assert_(issubclass(np.integer, numbers.Integral))
assert_(issubclass(np.signedinteger, numbers.Integral))
assert_(issubclass(np.unsignedinteger, numbers.Integral))
def test_floats(self):
for t in sctypes['float']:
assert_(isinstance(t(), numbers.Real),
f"{t.__name__} is not instance of Real")
assert_(issubclass(t, numbers.Real),
f"{t.__name__} is not subclass of Real")
assert_(not isinstance(t(), numbers.Rational),
f"{t.__name__} is instance of Rational")
assert_(not issubclass(t, numbers.Rational),
f"{t.__name__} is subclass of Rational")
def test_complex(self):
for t in sctypes['complex']:
assert_(isinstance(t(), numbers.Complex),
f"{t.__name__} is not instance of Complex")
assert_(issubclass(t, numbers.Complex),
f"{t.__name__} is not subclass of Complex")
assert_(not isinstance(t(), numbers.Real),
f"{t.__name__} is instance of Real")
assert_(not issubclass(t, numbers.Real),
f"{t.__name__} is subclass of Real")
def test_int(self):
for t in sctypes['int']:
assert_(isinstance(t(), numbers.Integral),
f"{t.__name__} is not instance of Integral")
assert_(issubclass(t, numbers.Integral),
f"{t.__name__} is not subclass of Integral")
def test_uint(self):
for t in sctypes['uint']:
assert_(isinstance(t(), numbers.Integral),
f"{t.__name__} is not instance of Integral")
assert_(issubclass(t, numbers.Integral),
f"{t.__name__} is not subclass of Integral")
.\numpy\numpy\_core\tests\test_api.py
import sys
import numpy as np
import numpy._core.umath as ncu
from numpy._core._rational_tests import rational
import pytest
from numpy.testing import (
assert_, assert_equal, assert_array_equal, assert_raises, assert_warns,
HAS_REFCOUNT
)
def test_array_array():
tobj = type(object)
ones11 = np.ones((1, 1), np.float64)
tndarray = type(ones11)
assert_equal(np.array(ones11, dtype=np.float64), ones11)
if HAS_REFCOUNT:
old_refcount = sys.getrefcount(tndarray)
np.array(ones11)
assert_equal(old_refcount, sys.getrefcount(tndarray))
assert_equal(np.array(None, dtype=np.float64),
np.array(np.nan, dtype=np.float64))
if HAS_REFCOUNT:
old_refcount = sys.getrefcount(tobj)
np.array(None, dtype=np.float64)
assert_equal(old_refcount, sys.getrefcount(tobj))
assert_equal(np.array(1.0, dtype=np.float64),
np.ones((), dtype=np.float64))
if HAS_REFCOUNT:
old_refcount = sys.getrefcount(np.float64)
np.array(np.array(1.0, dtype=np.float64), dtype=np.float64)
assert_equal(old_refcount, sys.getrefcount(np.float64))
S2 = np.dtype((bytes, 2))
S3 = np.dtype((bytes, 3))
S5 = np.dtype((bytes, 5))
assert_equal(np.array(b"1.0", dtype=np.float64),
np.ones((), dtype=np.float64))
assert_equal(np.array(b"1.0").dtype, S3)
assert_equal(np.array(b"1.0", dtype=bytes).dtype, S3)
assert_equal(np.array(b"1.0", dtype=S2), np.array(b"1."))
assert_equal(np.array(b"1", dtype=S5), np.ones((), dtype=S5))
U2 = np.dtype((str, 2))
U3 = np.dtype((str, 3))
U5 = np.dtype((str, 5))
assert_equal(np.array("1.0", dtype=np.float64),
np.ones((), dtype=np.float64))
assert_equal(np.array("1.0").dtype, U3)
assert_equal(np.array("1.0", dtype=str).dtype, U3)
assert_equal(np.array("1.0", dtype=U2), np.array(str("1.")))
assert_equal(np.array("1", dtype=U5), np.ones((), dtype=U5))
builtins = getattr(__builtins__, '__dict__', __builtins__)
assert_(hasattr(builtins, 'get'))
dat = np.array(memoryview(b'1.0'), dtype=np.float64)
assert_equal(dat, [49.0, 46.0, 48.0])
assert_(dat.dtype.type is np.float64)
dat = np.array(memoryview(b'1.0'))
assert_equal(dat, [49, 46, 48])
assert_(dat.dtype.type is np.uint8)
a = np.array(100.0, dtype=np.float64)
o = type("o", (object,),
dict(__array_interface__=a.__array_interface__))
assert_equal(np.array(o, dtype=np.float64), a)
a = np.array([(1, 4.0, 'Hello'), (2, 6.0, 'World')],
dtype=[('f0', int), ('f1', float), ('f2', str)])
o = type("o", (object,),
dict(__array_struct__=a.__array_struct__))
assert_equal(bytes(np.array(o).data), bytes(a.data))
def custom__array__(self, dtype=None, copy=None):
return np.array(100.0, dtype=dtype, copy=copy)
o = type("o", (object,), dict(__array__=custom__array__))()
assert_equal(np.array(o, dtype=np.float64), np.array(100.0, np.float64))
nested = 1.5
for i in range(ncu.MAXDIMS):
nested = [nested]
np.array(nested)
assert_raises(ValueError, np.array, [nested], dtype=np.float64)
assert_equal(np.array([None] * 10, dtype=np.float32),
np.full((10,), np.nan, dtype=np.float32))
assert_equal(np.array([[None]] * 10, dtype=np.float32),
np.full((10, 1), np.nan, dtype=np.float32))
assert_equal(np.array([[None] * 10], dtype=np.float32),
np.full((1, 10), np.nan, dtype=np.float32))
assert_equal(np.array([[None] * 10] * 10, dtype=np.float32),
np.full((10, 10), np.nan, dtype=np.float32))
assert_equal(np.array([None] * 10, dtype=np.float64),
np.full((10,), np.nan, dtype=np.float64))
assert_equal(np.array([[None]] * 10, dtype=np.float64),
np.full((10, 1), np.nan, dtype=np.float64))
assert_equal(np.array([[None] * 10], dtype=np.float64),
np.full((1, 10), np.nan, dtype=np.float64))
assert_equal(np.array([[None] * 10] * 10, dtype=np.float64),
np.full((10, 10), np.nan, dtype=np.float64))
assert_equal(np.array([1.0] * 10, dtype=np.float64),
np.ones((10,), dtype=np.float64))
assert_equal(np.array([[1.0]] * 10, dtype=np.float64),
np.ones((10, 1), dtype=np.float64))
assert_equal(np.array([[1.0] * 10], dtype=np.float64),
np.ones((1, 10), dtype=np.float64))
assert_equal(np.array([[1.0] * 10] * 10, dtype=np.float64),
np.ones((10, 10), dtype=np.float64))
assert_equal(np.array((None,) * 10, dtype=np.float64),
np.full((10,), np.nan, dtype=np.float64))
assert_equal(np.array([(None,)] * 10, dtype=np.float64),
np.full((10, 1), np.nan, dtype=np.float64))
assert_equal(np.array([(None,) * 10], dtype=np.float64),
np.full((1, 10), np.nan, dtype=np.float64))
assert_equal(np.array([(None,) * 10] * 10, dtype=np.float64),
np.full((10, 10), np.nan, dtype=np.float64))
assert_equal(np.array((1.0,) * 10, dtype=np.float64),
np.ones((10,), dtype=np.float64))
assert_equal(np.array([(1.0,)] * 10, dtype=np.float64),
np.ones((10, 1), dtype=np.float64))
assert_equal(np.array([(1.0,) * 10], dtype=np.float64),
np.ones((1, 10), dtype=np.float64))
assert_equal(np.array([(1.0,) * 10] * 10, dtype=np.float64),
np.ones((10, 10), dtype=np.float64))
@pytest.mark.parametrize("array", [True, False])
def test_array_impossible_casts(array):
rt = rational(1, 2)
if array:
rt = np.array(rt)
with assert_raises(TypeError):
np.array(rt, dtype="M8")
def test_array_astype():
a = np.arange(6, dtype='f4').reshape(2, 3)
b = a.astype('i4')
assert_equal(a, b)
assert_equal(b.dtype, np.dtype('i4'))
assert_equal(a.strides, b.strides)
b = a.T.astype('i4')
assert_equal(a.T, b)
assert_equal(b.dtype, np.dtype('i4'))
assert_equal(a.T.strides, b.strides)
b = a.astype('f4')
assert_equal(a, b)
assert_(not (a is b))
b = a.astype('f4', copy=False)
assert_(a is b)
b = a.astype('f4', order='F', copy=False)
assert_equal(a, b)
assert_(not (a is b))
assert_(b.flags.f_contiguous)
b = a.astype('f4', order='C', copy=False)
assert_equal(a, b)
assert_(a is b)
assert_(b.flags.c_contiguous)
b = a.astype('c8', casting='safe')
assert_equal(a, b)
assert_equal(b.dtype, np.dtype('c8'))
assert_raises(TypeError, a.astype, 'i4', casting='safe')
b = a.astype('f4', subok=0, copy=False)
assert_(a is b)
class MyNDArray(np.ndarray):
pass
a = np.array([[0, 1, 2], [3, 4, 5]], dtype='f4').view(MyNDArray)
b = a.astype('f4', subok=True, copy=False)
assert_(a is b)
b = a.astype('i4', copy=False)
assert_equal(a, b)
assert_equal(type(b), MyNDArray)
b = a.astype('f4', subok=False, copy=False)
assert_equal(a, b)
assert_(not (a is b))
assert_(type(b) is not MyNDArray)
a = np.array([b'a'*100], dtype='O')
b = a.astype('S')
assert_equal(a, b)
assert_equal(b.dtype, np.dtype('S100'))
a = np.array(['a'*100], dtype='O')
b = a.astype('U')
assert_equal(a, b)
assert_equal(b.dtype, np.dtype('U100'))
a = np.array([b'a'*10], dtype='O')
b = a.astype('S')
assert_equal(a, b)
assert_equal(b.dtype, np.dtype('S10'))
a = np.array(['a'*10], dtype='O')
b = a.astype('U')
assert_equal(a, b)
assert_equal(b.dtype, np.dtype('U10'))
a = np.array(123456789012345678901234567890, dtype='O').astype('S')
assert_array_equal(a, np.array(b'1234567890' * 3, dtype='S30'))
a = np.array(123456789012345678901234567890, dtype='O').astype('U')
assert_array_equal(a, np.array('1234567890' * 3, dtype='U30'))
a = np.array([123456789012345678901234567890], dtype='O').astype('S')
assert_array_equal(a, np.array(b'1234567890' * 3, dtype='S30'))
a = np.array(123456789012345678901234567890, dtype='S')
assert_array_equal(a, np.array(b'1234567890' * 3, dtype='S30'))
a = np.array('a\u0140', dtype='U')
b = np.ndarray(buffer=a, dtype='uint32', shape=2)
assert_(b.size == 2)
a = np.array([1000], dtype='i4')
assert_raises(TypeError, a.astype, 'S1', casting='safe')
a = np.array(1000, dtype='i4')
assert_raises(TypeError, a.astype, 'U1', casting='safe')
assert_raises(TypeError, a.astype)
@pytest.mark.parametrize("dt", ["S", "U"])
def test_array_astype_to_string_discovery_empty(dt):
arr = np.array([""], dtype=object)
assert arr.astype(dt).dtype.itemsize == np.dtype(f"{dt}1").itemsize
assert np.can_cast(arr, dt, casting="unsafe")
assert not np.can_cast(arr, dt, casting="same_kind")
assert np.can_cast("O", dt, casting="unsafe")
@pytest.mark.parametrize("dt", ["d", "f", "S13", "U32"])
def test_array_astype_to_void(dt):
dt = np.dtype(dt)
arr = np.array([], dtype=dt)
assert arr.astype("V").dtype.itemsize == dt.itemsize
def test_object_array_astype_to_void():
arr = np.array([], dtype="O").astype("V")
assert arr.dtype == "V8"
@pytest.mark.parametrize("t", np._core.sctypes['uint'] + np._core.sctypes['int'] + np._core.sctypes['float'])
def test_array_astype_warning(t):
a = np.array(10, dtype=np.complex128)
assert_warns(np.exceptions.ComplexWarning, a.astype, t)
@pytest.mark.parametrize(["dtype", "out_dtype"],
[(np.bytes_, np.bool),
(np.str_, np.bool),
(np.dtype("S10,S9"), np.dtype("?,?")),
(np.dtype("S7,U9"), np.dtype("?,?"))])
def test_string_to_boolean_cast(dtype, out_dtype):
arr = np.array(
["10", "10\0\0\0", "0\0\0", "0", "False", " ", "", "\0"],
dtype=dtype)
expected = np.array(
[True, True, True, True, True, True, False, False],
dtype=out_dtype)
assert_array_equal(arr.astype(out_dtype), expected)
assert_array_equal(np.nonzero(arr), np.nonzero(expected))
@pytest.mark.parametrize("str_type", [str, bytes, np.str_])
@pytest.mark.parametrize("scalar_type",
[np.complex64, np.complex128, np.clongdouble])
def test_string_to_complex_cast(str_type, scalar_type):
value = scalar_type(b"1+3j")
assert scalar_type(value) == 1+3j
assert np.array([value], dtype=object).astype(scalar_type)[()] == 1+3j
assert np.array(value).astype(scalar_type)[()] == 1+3j
arr = np.zeros(1, dtype=scalar_type)
arr[0] = value
assert arr[0] == 1+3j
@pytest.mark.parametrize("dtype", np.typecodes["AllFloat"])
def test_none_to_nan_cast(dtype):
arr = np.zeros(1, dtype=dtype)
arr[0] = None
assert np.isnan(arr)[0]
assert np.isnan(np.array(None, dtype=dtype))[()]
assert np.isnan(np.array([None], dtype=dtype))[0]
assert np.isnan(np.array(None).astype(dtype))[()]
def test_copyto_fromscalar():
a = np.arange(6, dtype='f4').reshape(2, 3)
np.copyto(a, 1.5)
assert_equal(a, 1.5)
np.copyto(a.T, 2.5)
assert_equal(a, 2.5)
mask = np.array([[0, 1, 0], [0, 0, 1]], dtype='?')
np.copyto(a, 3.5, where=mask)
assert_equal(a, [[2.5, 3.5, 2.5], [2.5, 2.5, 3.5]])
mask = np.array([[0, 1], [1, 1], [1, 0]], dtype='?')
np.copyto(a.T, 4.5, where=mask)
assert_equal(a, [[2.5, 4.5, 4.5], [4.5, 4.5, 3.5]])
def test_copyto():
a = np.arange(6, dtype='i4').reshape(2, 3)
np.copyto(a, [[3, 1, 5], [6, 2, 1]])
assert_equal(a, [[3, 1, 5], [6, 2, 1]])
np.copyto(a[:, :2], a[::-1, 1::-1])
assert_equal(a, [[2, 6, 5], [1, 3, 1]])
assert_raises(TypeError, np.copyto, a, 1.5)
np.copyto(a, 1.5, casting='unsafe')
assert_equal(a, 1)
np.copyto(a, 3, where=[True, False, True])
assert_equal(a, [[3, 1, 3], [3, 1, 3]])
assert_raises(TypeError, np.copyto, a, 3.5, where=[True, False, True])
np.copyto(a, 4.0, casting='unsafe', where=[[0, 1, 1], [1, 0, 0]])
assert_equal(a, [[3, 4, 4], [4, 1, 3]])
np.copyto(a[:, :2], a[::-1, 1::-1], where=[[0, 1], [1, 1]])
assert_equal(a, [[3, 4, 4], [4, 3, 3]])
assert_raises(TypeError, np.copyto, [1, 2, 3], [2, 3, 4])
def test_copyto_permut():
pad = 500
l = [True] * pad + [True, True, True, True]
r = np.zeros(len(l)-pad)
d = np.ones(len(l)-pad)
mask = np.array(l)[pad:]
np.copyto(r, d, where=mask[::-1])
power = 9
d = np.ones(power)
for i in range(2**power):
r = np.zeros(power)
l = [(i & x) != 0 for x in range(power)]
mask = np.array(l)
np.copyto(r, d, where=mask)
assert_array_equal(r == 1, l)
assert_equal(r.sum(), sum(l))
r = np.zeros(power)
np.copyto(r, d, where=mask[::-1])
assert_array_equal(r == 1, l[::-1])
assert_equal(r.sum(), sum(l))
r = np.zeros(power)
np.copyto(r[::2], d[::2], where=mask[::2])
assert_array_equal(r[::2] == 1, l[::2])
assert_equal(r[::2].sum(), sum(l[::2]))
r = np.zeros(power)
np.copyto(r[::2], d[::2], where=mask[::-2])
assert_array_equal(r[::2] == 1, l[::-2])
assert_equal(r[::2].sum(), sum(l[::-2]))
for c in [0xFF, 0x7F, 0x02, 0x10]:
r = np.zeros(power)
mask = np.array(l)
imask = np.array(l).view(np.uint8)
imask[mask != 0] = c
np.copyto(r, d, where=mask)
assert_array_equal(r == 1, l)
assert_equal(r.sum(), sum(l))
r = np.zeros(power)
np.copyto(r, d, where=True)
assert_equal(r.sum(), r.size)
r = np.ones(power)
d = np.zeros(power)
np.copyto(r, d, where=False)
assert_equal(r.sum(), r.size)
def test_copy_order():
a = np.arange(24).reshape(2, 1, 3, 4)
b = a.copy(order='F')
c = np.arange(24).reshape(2, 1, 4, 3).swapaxes(2, 3)
def check_copy_result(x, y, ccontig, fcontig, strides=False):
assert_(not (x is y))
assert_equal(x, y)
assert_equal(x.flags.c_contiguous, ccontig)
assert_equal(x.flags.f_contiguous, fcontig)
assert_(a.flags.c_contiguous)
assert_(not a.flags.f_contiguous)
assert_(not b.flags.c_contiguous)
assert_(b.flags.f_contiguous)
assert_(not c.flags.c_contiguous)
assert_(not c.flags.f_contiguous)
res = a.copy(order='C')
check_copy_result(res, a, ccontig=True, fcontig=False, strides=True)
res = b.copy(order='C')
check_copy_result(res, b, ccontig=True, fcontig=False, strides=False)
res = c.copy(order='C')
check_copy_result(res, c, ccontig=True, fcontig=False, strides=False)
res = np.copy(a, order='C')
check_copy_result(res, a, ccontig=True, fcontig=False, strides=True)
res = np.copy(b, order='C')
check_copy_result(res, b, ccontig=True, fcontig=False, strides=False)
res = np.copy(c, order='C')
check_copy_result(res, c, ccontig=True, fcontig=False, strides=False)
res = a.copy(order='F')
check_copy_result(res, a, ccontig=False, fcontig=True, strides=False)
res = b.copy(order='F')
check_copy_result(res, b, ccontig=False, fcontig=True, strides=True)
res = c.copy(order='F')
check_copy_result(res, c, ccontig=False, fcontig=True, strides=False)
res = np.copy(a, order='F')
check_copy_result(res, a, ccontig=False, fcontig=True, strides=False)
res = np.copy(b, order='F')
check_copy_result(res, b, ccontig=False, fcontig=True, strides=True)
res = np.copy(c, order='F')
check_copy_result(res, c, ccontig=False, fcontig=True, strides=False)
res = a.copy(order='K')
check_copy_result(res, a, ccontig=True, fcontig=False, strides=True)
res = b.copy(order='K')
check_copy_result(res, b, ccontig=False, fcontig=True, strides=True)
res = c.copy(order='K')
check_copy_result(res, c, ccontig=False, fcontig=False, strides=True)
res = np.copy(a, order='K')
check_copy_result(res, a, ccontig=True, fcontig=False, strides=True)
res = np.copy(b, order='K')
check_copy_result(res, b, ccontig=False, fcontig=True, strides=True)
res = np.copy(c, order='K')
check_copy_result(res, c, ccontig=False, fcontig=False, strides=True)
def test_contiguous_flags():
a = np.ones((4, 4, 1))[::2,:,:]
a.strides = a.strides[:2] + (-123,)
b = np.ones((2, 2, 1, 2, 2)).swapaxes(3, 4)
def check_contig(a, ccontig, fcontig):
assert_(a.flags.c_contiguous == ccontig)
assert_(a.flags.f_contiguous == fcontig)
check_contig(a, False, False)
check_contig(b, False, False)
check_contig(np.empty((2, 2, 0, 2, 2)), True, True)
check_contig(np.array([[[1], [2]]], order='F'), True, True)
check_contig(np.empty((2, 2)), True, False)
check_contig(np.empty((2, 2), order='F'), False, True)
check_contig(np.array(a, copy=None), False, False)
check_contig(np.array(a, copy=None, order='C'), True, False)
check_contig(np.array(a, ndmin=4, copy=None, order='F'), False, True)
check_contig(a[0], True, True)
check_contig(a[None, ::4, ..., None], True, True)
check_contig(b[0, 0, ...], False, True)
check_contig(b[:, :, 0:0, :, :], True, True)
check_contig(a.ravel(), True, True)
check_contig(np.ones((1, 3, 1)).squeeze(), True, True)
def test_broadcast_arrays():
a = np.array([(1, 2, 3)], dtype='u4,u4,u4')
b = np.array([(1, 2, 3), (4, 5, 6), (7, 8, 9)], dtype='u4,u4,u4')
result = np.broadcast_arrays(a, b)
assert_equal(result[0], np.array([(1, 2, 3), (1, 2, 3), (1, 2, 3)], dtype='u4,u4,u4'))
assert_equal(result[1], np.array([(1, 2, 3), (4, 5, 6), (7, 8, 9)], dtype='u4,u4,u4'))
@pytest.mark.parametrize(["shape", "fill_value", "expected_output"],
[((2, 2), [5.0, 6.0], np.array([[5.0, 6.0], [5.0, 6.0]])),
((3, 2), [1.0, 2.0], np.array([[1.0, 2.0], [1.0, 2.0], [1.0, 2.0]]))])
def test_full_from_list(shape, fill_value, expected_output):
output = np.full(shape, fill_value)
assert_equal(output, expected_output)
def test_astype_copyflag():
arr = np.arange(10, dtype=np.intp)
res_true = arr.astype(np.intp, copy=True)
assert not np.shares_memory(arr, res_true)
res_false = arr.astype(np.intp, copy=False)
assert np.shares_memory(arr, res_false)
res_false_float = arr.astype(np.float64, copy=False)
assert not np.shares_memory(arr, res_false_float)
assert_raises(ValueError, arr.astype, np.float64,
copy=np._CopyMode.NEVER)
.\numpy\numpy\_core\tests\test_argparse.py
"""
Tests for the private NumPy argument parsing functionality.
They mainly exists to ensure good test coverage without having to try the
weirder cases on actual numpy functions but test them in one place.
The test function is defined in C to be equivalent to (errors may not always
match exactly, and could be adjusted):
def func(arg1, /, arg2, *, arg3):
i = integer(arg1) # reproducing the 'i' parsing in Python.
return None
"""
import pytest
import numpy as np
from numpy._core._multiarray_tests import argparse_example_function as func
def test_invalid_integers():
with pytest.raises(TypeError,
match="integer argument expected, got float"):
func(1.)
with pytest.raises(OverflowError):
func(2**100)
def test_missing_arguments():
with pytest.raises(TypeError,
match="missing required positional argument 0"):
func()
with pytest.raises(TypeError,
match="missing required positional argument 0"):
func(arg2=1, arg3=4)
with pytest.raises(TypeError,
match=r"missing required argument 'arg2' \(pos 1\)"):
func(1, arg3=5)
def test_too_many_positional():
with pytest.raises(TypeError,
match="takes from 2 to 3 positional arguments but 4 were given"):
func(1, 2, 3, 4)
def test_multiple_values():
with pytest.raises(TypeError,
match=r"given by name \('arg2'\) and position \(position 1\)"):
func(1, 2, arg2=3)
def test_string_fallbacks():
arg2 = np.str_("arg2")
missing_arg = np.str_("missing_arg")
func(1, **{arg2: 3})
with pytest.raises(TypeError,
match="got an unexpected keyword argument 'missing_arg'"):
func(2, **{missing_arg: 3})
def test_too_many_arguments_method_forwarding():
arr = np.arange(3)
args = range(1000)
with pytest.raises(TypeError):
arr.mean(*args)
.\numpy\numpy\_core\tests\test_arraymethod.py
"""
This file tests the generic aspects of ArrayMethod. At the time of writing
this is private API, but when added, public API may be added here.
"""
import sys
import types
from typing import Any
import pytest
import numpy as np
from numpy._core._multiarray_umath import _get_castingimpl as get_castingimpl
class TestResolveDescriptors:
method = get_castingimpl(type(np.dtype("d")), type(np.dtype("f")))
@pytest.mark.parametrize("args", [
(True,),
((None,)),
((None, None, None),),
((None, None),),
((np.dtype("d"), True),),
((np.dtype("f"), None),),
])
def test_invalid_arguments(self, args):
with pytest.raises(TypeError):
self.method._resolve_descriptors(*args)
class TestSimpleStridedCall:
method = get_castingimpl(type(np.dtype("d")), type(np.dtype("f")))
@pytest.mark.parametrize(["args", "error"], [
((True,), TypeError),
(((None,),), TypeError),
((None, None), TypeError),
(((None, None, None),), TypeError),
(((np.arange(3), np.arange(3)),), TypeError),
(((np.ones(3, dtype=">d"), np.ones(3, dtype="<f")),), TypeError),
(((np.ones((2, 2), dtype="d"), np.ones((2, 2), dtype="f")),), ValueError),
(((np.ones(3, dtype="d"), np.ones(4, dtype="f")),), ValueError),
(((np.frombuffer(b"\0x00"*3*2, dtype="d"), np.frombuffer(b"\0x00"*3, dtype="f")),), ValueError),
])
def test_invalid_arguments(self, args, error):
with pytest.raises(error):
self.method._simple_strided_call(*args)
@pytest.mark.parametrize(
"cls", [
np.ndarray, np.recarray, np.char.chararray, np.matrix, np.memmap
]
)
class TestClassGetItem:
def test_class_getitem(self, cls: type[np.ndarray]) -> None:
"""Test `ndarray.__class_getitem__`."""
alias = cls[Any, Any]
assert isinstance(alias, types.GenericAlias)
assert alias.__origin__ is cls
@pytest.mark.parametrize("arg_len", range(4))
def test_subscript_tup(self, cls: type[np.ndarray], arg_len: int) -> None:
arg_tup = (Any,) * arg_len
if arg_len in (1, 2):
assert cls[arg_tup]
else:
match = f"Too {'few' if arg_len == 0 else 'many'} arguments"
with pytest.raises(TypeError, match=match):
cls[arg_tup]
.\numpy\numpy\_core\tests\test_arrayobject.py
import pytest
import numpy as np
from numpy.testing import assert_array_equal
def test_matrix_transpose_raises_error_for_1d():
msg = "matrix transpose with ndim < 2 is undefined"
arr = np.arange(48)
with pytest.raises(ValueError, match=msg):
arr.mT
def test_matrix_transpose_equals_transpose_2d():
arr = np.arange(48).reshape((6, 8))
assert_array_equal(arr.T, arr.mT)
ARRAY_SHAPES_TO_TEST = (
(5, 2),
(5, 2, 3),
(5, 2, 3, 4),
)
@pytest.mark.parametrize("shape", ARRAY_SHAPES_TO_TEST)
def test_matrix_transpose_equals_swapaxes(shape):
num_of_axes = len(shape)
vec = np.arange(shape[-1])
arr = np.broadcast_to(vec, shape)
tgt = np.swapaxes(arr, num_of_axes - 2, num_of_axes - 1)
mT = arr.mT
assert_array_equal(tgt, mT)
.\numpy\numpy\_core\tests\test_arrayprint.py
import sys
import gc
from hypothesis import given
from hypothesis.extra import numpy as hynp
import pytest
import numpy as np
from numpy.testing import (
assert_, assert_equal, assert_raises, assert_warns, HAS_REFCOUNT,
assert_raises_regex,
)
from numpy._core.arrayprint import _typelessdata
import textwrap
class TestArrayRepr:
def test_nan_inf(self):
x = np.array([np.nan, np.inf])
assert_equal(repr(x), 'array([nan, inf])')
def test_subclass(self):
class sub(np.ndarray): pass
x1d = np.array([1, 2]).view(sub)
assert_equal(repr(x1d), 'sub([1, 2])')
x2d = np.array([[1, 2], [3, 4]]).view(sub)
assert_equal(repr(x2d),
'sub([[1, 2],\n'
' [3, 4]])')
xstruct = np.ones((2,2), dtype=[('a', '<i4')]).view(sub)
assert_equal(repr(xstruct),
"sub([[(1,), (1,)],\n"
" [(1,), (1,)]]"
", dtype=[('a', '<i4')])"
)
@pytest.mark.xfail(reason="See gh-10544")
def test_object_subclass(self):
class sub(np.ndarray):
def __new__(cls, inp):
obj = np.asarray(inp).view(cls)
return obj
def __getitem__(self, ind):
ret = super().__getitem__(ind)
return sub(ret)
x = sub([None, None])
assert_equal(repr(x), 'sub([None, None], dtype=object)')
assert_equal(str(x), '[None None]')
x = sub([None, sub([None, None])])
assert_equal(repr(x),
'sub([None, sub([None, None], dtype=object)], dtype=object)')
assert_equal(str(x), '[None sub([None, None], dtype=object)]')
def test_0d_object_subclass(self):
class sub(np.ndarray):
def __new__(cls, inp):
obj = np.asarray(inp).view(cls)
return obj
def __getitem__(self, ind):
ret = super().__getitem__(ind)
return sub(ret)
x = sub(1)
assert_equal(repr(x), 'sub(1)')
assert_equal(str(x), '1')
x = sub([1, 1])
assert_equal(repr(x), 'sub([1, 1])')
assert_equal(str(x), '[1 1]')
x = sub(None)
assert_equal(repr(x), 'sub(None, dtype=object)')
assert_equal(str(x), 'None')
y = sub(None)
x[()] = y
y[()] = x
assert_equal(repr(x),
'sub(sub(sub(..., dtype=object), dtype=object), dtype=object)')
assert_equal(str(x), '...')
x[()] = 0
x = sub(None)
x[()] = sub(None)
assert_equal(repr(x), 'sub(sub(None, dtype=object), dtype=object)')
assert_equal(str(x), 'None')
class DuckCounter(np.ndarray):
def __getitem__(self, item):
result = super().__getitem__(item)
if not isinstance(result, DuckCounter):
result = result[...].view(DuckCounter)
return result
def to_string(self):
return {0: 'zero', 1: 'one', 2: 'two'}.get(self.item(), 'many')
def __str__(self):
if self.shape == ():
return self.to_string()
else:
fmt = {'all': lambda x: x.to_string()}
return np.array2string(self, formatter=fmt)
dc = np.arange(5).view(DuckCounter)
assert_equal(str(dc), "[zero one two many many]")
assert_equal(str(dc[0]), "zero")
def test_self_containing(self):
arr0d = np.array(None)
arr0d[()] = arr0d
assert_equal(repr(arr0d),
'array(array(..., dtype=object), dtype=object)')
arr0d[()] = 0
arr1d = np.array([None, None])
arr1d[1] = arr1d
assert_equal(repr(arr1d),
'array([None, array(..., dtype=object)], dtype=object)')
arr1d[1] = 0
first = np.array(None)
second = np.array(None)
first[()] = second
second[()] = first
assert_equal(repr(first),
'array(array(array(..., dtype=object), dtype=object), dtype=object)')
first[()] = 0
arr1d = np.array([None, None])
arr1d[0] = [1, 2]
arr1d[1] = [3]
assert_equal(repr(arr1d),
'array([list([1, 2]), list([3])], dtype=object)')
repr(np.void(b'test'))
no_fields = np.dtype([])
arr_no_fields = np.empty(4, dtype=no_fields)
assert_equal(repr(arr_no_fields), 'array([(), (), (), ()], dtype=[])')
class TestComplexArray:
def test_str(self):
rvals = [0, 1, -1, np.inf, -np.inf, np.nan]
cvals = [complex(rp, ip) for rp in rvals for ip in rvals]
dtypes = [np.complex64, np.cdouble, np.clongdouble]
actual = [str(np.array([c], dt)) for c in cvals for dt in dtypes]
wanted = [
'[0.+0.j]', '[0.+0.j]', '[0.+0.j]',
'[0.+1.j]', '[0.+1.j]', '[0.+1.j]',
'[0.-1.j]', '[0.-1.j]', '[0.-1.j]',
'[0.+infj]', '[0.+infj]', '[0.+infj]',
'[0.-infj]', '[0.-infj]', '[0.-infj]',
'[0.+nanj]', '[0.+nanj]', '[0.+nanj]',
'[1.+0.j]', '[1.+0.j]', '[1.+0.j]',
'[1.+1.j]', '[1.+1.j]', '[1.+1.j]',
'[1.-1.j]', '[1.-1.j]', '[1.-1.j]',
'[1.+infj]', '[1.+infj]', '[1.+infj]',
'[1.-infj]', '[1.-infj]', '[1.-infj]',
'[1.+nanj]', '[1.+nanj]', '[1.+nanj]',
'[-1.+0.j]', '[-1.+0.j]', '[-1.+0.j]',
'[-1.+1.j]', '[-1.+1.j]', '[-1.+1.j]',
'[-1.-1.j]', '[-1.-1.j]', '[-1.-1.j]',
'[-1.+infj]', '[-1.+infj]', '[-1.+infj]',
'[-1.-infj]', '[-1.-infj]', '[-1.-infj]',
'[-1.+nanj]', '[-1.+nanj]', '[-1.+nanj]',
'[inf+0.j]', '[inf+0.j]', '[inf+0.j]',
'[inf+1.j]', '[inf+1.j]', '[inf+1.j]',
'[inf-1.j]', '[inf-1.j]', '[inf-1.j]',
'[inf+infj]', '[inf+infj]', '[inf+infj]',
'[inf-infj]', '[inf-infj]', '[inf-infj]',
'[inf+nanj]', '[inf+nanj]', '[inf+nanj]',
'[-inf+0.j]', '[-inf+0.j]', '[-inf+0.j]',
'[-inf+1.j]', '[-inf+1.j]', '[-inf+1.j]',
'[-inf-1.j]', '[-inf-1.j]', '[-inf-1.j]',
'[-inf+infj]', '[-inf+infj]', '[-inf+infj]',
'[-inf-infj]', '[-inf-infj]', '[-inf-infj]',
'[-inf+nanj]', '[-inf+nanj]', '[-inf+nanj]',
'[nan+0.j]', '[nan+0.j]', '[nan+0.j]',
'[nan+1.j]', '[nan+1.j]', '[nan+1.j]',
'[nan-1.j]', '[nan-1.j]', '[nan-1.j]',
'[nan+infj]', '[nan+infj]', '[nan+infj]',
'[nan-infj]', '[nan-infj]', '[nan-infj]',
'[nan+nanj]', '[nan+nanj]', '[nan+nanj]']
for res, val in zip(actual, wanted):
assert_equal(res, val)
class TestArray2String:
def test_basic(self):
"""Basic test of array2string."""
a = np.arange(3)
assert_(np.array2string(a) == '[0 1 2]')
assert_(np.array2string(a, max_line_width=4, legacy='1.13') == '[0 1\n 2]')
assert_(np.array2string(a, max_line_width=4) == '[0\n 1\n 2]')
def test_unexpected_kwarg(self):
with assert_raises_regex(TypeError, 'nonsense'):
np.array2string(np.array([1, 2, 3]),
nonsense=None)
def test_format_function(self):
"""Test custom format function for each element in array."""
def _format_function(x):
if np.abs(x) < 1:
return '.'
elif np.abs(x) < 2:
return 'o'
else:
return 'O'
x = np.arange(3)
x_hex = "[0x0 0x1 0x2]"
x_oct = "[0o0 0o1 0o2]"
assert_(np.array2string(x, formatter={'all':_format_function}) ==
"[. o O]")
assert_(np.array2string(x, formatter={'int_kind':_format_function}) ==
"[. o O]")
assert_(np.array2string(x, formatter={'all':lambda x: "%.4f" % x}) ==
"[0.0000 1.0000 2.0000]")
assert_equal(np.array2string(x, formatter={'int':lambda x: hex(x)}),
x_hex)
assert_equal(np.array2string(x, formatter={'int':lambda x: oct(x)}),
x_oct)
x = np.arange(3.)
assert_(np.array2string(x, formatter={'float_kind':lambda x: "%.2f" % x}) ==
"[0.00 1.00 2.00]")
assert_(np.array2string(x, formatter={'float':lambda x: "%.2f" % x}) ==
"[0.00 1.00 2.00]")
s = np.array(['abc', 'def'])
assert_(np.array2string(s, formatter={'numpystr':lambda s: s*2}) ==
'[abcabc defdef]')
def test_structure_format_mixed(self):
dt = np.dtype([('name', np.str_, 16), ('grades', np.float64, (2,))])
x = np.array([('Sarah', (8.0, 7.0)), ('John', (6.0, 7.0))], dtype=dt)
assert_equal(np.array2string(x),
"[('Sarah', [8., 7.]) ('John', [6., 7.])]")
np.set_printoptions(legacy='1.13')
try:
A = np.zeros(shape=10, dtype=[("A", "M8[s]")])
A[5:].fill(np.datetime64('NaT'))
assert_equal(
np.array2string(A),
textwrap.dedent("""\
[('1970-01-01T00:00:00',) ('1970-01-01T00:00:00',) ('1970-01-01T00:00:00',)
('1970-01-01T00:00:00',) ('1970-01-01T00:00:00',) ('NaT',) ('NaT',)
('NaT',) ('NaT',) ('NaT',)]""")
)
finally:
np.set_printoptions(legacy=False)
assert_equal(
np.array2string(A),
textwrap.dedent("""\
[('1970-01-01T00:00:00',) ('1970-01-01T00:00:00',)
('1970-01-01T00:00:00',) ('1970-01-01T00:00:00',)
('1970-01-01T00:00:00',) ( 'NaT',)
( 'NaT',) ( 'NaT',)
( 'NaT',) ( 'NaT',)]""")
)
A = np.full(10, 123456, dtype=[("A", "m8[s]")])
A[5:].fill(np.datetime64('NaT'))
assert_equal(
np.array2string(A),
textwrap.dedent("""\
[(123456,) (123456,) (123456,) (123456,) (123456,) ( 'NaT',) ( 'NaT',)
( 'NaT',) ( 'NaT',) ( 'NaT',)]""")
)
def test_structure_format_int(self):
struct_int = np.array([([1, -1],), ([123, 1],)],
dtype=[('B', 'i4', 2)])
assert_equal(np.array2string(struct_int),
"[([ 1, -1],) ([123, 1],)]")
struct_2dint = np.array([([[0, 1], [2, 3]],), ([[12, 0], [0, 0]],)],
dtype=[('B', 'i4', (2, 2))])
assert_equal(np.array2string(struct_2dint),
"[([[ 0, 1], [ 2, 3]],) ([[12, 0], [ 0, 0]],)]")
def test_structure_format_float(self):
array_scalar = np.array(
(1., 2.1234567890123456789, 3.), dtype=('f8,f8,f8'))
assert_equal(np.array2string(array_scalar), "(1., 2.12345679, 3.)")
def test_unstructured_void_repr(self):
a = np.array([27, 91, 50, 75, 7, 65, 10, 8,
27, 91, 51, 49,109, 82,101,100], dtype='u1').view('V8')
assert_equal(repr(a[0]),
r"np.void(b'\x1B\x5B\x32\x4B\x07\x41\x0A\x08')")
assert_equal(str(a[0]), r"b'\x1B\x5B\x32\x4B\x07\x41\x0A\x08'")
assert_equal(repr(a),
r"array([b'\x1B\x5B\x32\x4B\x07\x41\x0A\x08'," "\n"
r" b'\x1B\x5B\x33\x31\x6D\x52\x65\x64'], dtype='|V8')")
assert_equal(eval(repr(a), vars(np)), a)
assert_equal(eval(repr(a[0]), dict(np=np)), a[0])
def test_edgeitems_kwarg(self):
arr = np.zeros(3, int)
assert_equal(
np.array2string(arr, edgeitems=1, threshold=0),
"[0 ... 0]"
)
def test_summarize_1d(self):
A = np.arange(1001)
strA = '[ 0 1 2 ... 998 999 1000]'
assert_equal(str(A), strA)
reprA = 'array([ 0, 1, 2, ..., 998, 999, 1000])'
assert_equal(repr(A), reprA)
def test_summarize_2d(self):
A = np.arange(1002).reshape(2, 501)
strA = '[[ 0 1 2 ... 498 499 500]\n' \
' [ 501 502 503 ... 999 1000 1001]]'
assert_equal(str(A), strA)
reprA = 'array([[ 0, 1, 2, ..., 498, 499, 500],\n' \
' [ 501, 502, 503, ..., 999, 1000, 1001]])'
assert_equal(repr(A), reprA)
def test_summarize_structure(self):
A = (np.arange(2002, dtype="<i8").reshape(2, 1001)
.view([('i', "<i8", (1001,))]))
strA = ("[[([ 0, 1, 2, ..., 998, 999, 1000],)]\n"
" [([1001, 1002, 1003, ..., 1999, 2000, 2001],)]]")
assert_equal(str(A), strA)
reprA = ("array([[([ 0, 1, 2, ..., 998, 999, 1000],)],\n"
" [([1001, 1002, 1003, ..., 1999, 2000, 2001],)]],\n"
" dtype=[('i', '<i8', (1001,))])")
assert_equal(repr(A), reprA)
B = np.ones(2002, dtype=">i8").view([('i', ">i8", (2, 1001))])
strB = "[([[1, 1, 1, ..., 1, 1, 1], [1, 1, 1, ..., 1, 1, 1]],)]"
assert_equal(str(B), strB)
reprB = (
"array([([[1, 1, 1, ..., 1, 1, 1], [1, 1, 1, ..., 1, 1, 1]],)],\n"
" dtype=[('i', '>i8', (2, 1001))])"
)
assert_equal(repr(B), reprB)
C = (np.arange(22, dtype="<i8").reshape(2, 11)
.view([('i1', "<i8"), ('i10', "<i8", (10,))]))
strC = "[[( 0, [ 1, ..., 10])]\n [(11, [12, ..., 21])]]"
assert_equal(np.array2string(C, threshold=1, edgeitems=1), strC)
def test_linewidth(self):
a = np.full(6, 1)
def make_str(a, width, **kw):
return np.array2string(a, separator="", max_line_width=width, **kw)
assert_equal(make_str(a, 8, legacy='1.13'), '[111111]')
assert_equal(make_str(a, 7, legacy='1.13'), '[111111]')
assert_equal(make_str(a, 5, legacy='1.13'), '[1111\n'
' 11]')
assert_equal(make_str(a, 8), '[111111]')
assert_equal(make_str(a, 7), '[11111\n'
' 1]')
assert_equal(make_str(a, 5), '[111\n'
' 111]')
b = a[None,None,:]
assert_equal(make_str(b, 12, legacy='1.13'), '[[[111111]]]')
assert_equal(make_str(b, 9, legacy='1.13'), '[[[111111]]]')
assert_equal(make_str(b, 8, legacy='1.13'), '[[[11111\n'
' 1]]]')
assert_equal(make_str(b, 12), '[[[111111]]]')
assert_equal(make_str(b, 9), '[[[111\n'
' 111]]]')
assert_equal(make_str(b, 8), '[[[11\n'
' 11\n'
' 11]]]')
def test_wide_element(self):
a = np.array(['xxxxx'])
assert_equal(
np.array2string(a, max_line_width=5),
"['xxxxx']"
)
assert_equal(
np.array2string(a, max_line_width=5, legacy='1.13'),
"[ 'xxxxx']"
)
def test_multiline_repr(self):
class MultiLine:
def __repr__(self):
return "Line 1\nLine 2"
a = np.array([[None, MultiLine()], [MultiLine(), None]])
assert_equal(
np.array2string(a),
'[[None Line 1\n'
' Line 2]\n'
' [Line 1\n'
' Line 2 None]]'
)
assert_equal(
np.array2string(a, max_line_width=5),
'[[None\n'
' Line 1\n'
' Line 2]\n'
' [Line 1\n'
' Line 2\n'
' None]]'
)
assert_equal(
repr(a),
'array([[None, Line 1\n'
' Line 2],\n'
' [Line 1\n'
' Line 2, None]], dtype=object)'
)
class MultiLineLong:
def __repr__(self):
return "Line 1\nLooooooooooongestLine2\nLongerLine 3"
a = np.array([[None, MultiLineLong()], [MultiLineLong(), None]])
assert_equal(
repr(a),
'array([[None, Line 1\n'
' LooooooooooongestLine2\n'
' LongerLine 3 ],\n'
' [Line 1\n'
' LooooooooooongestLine2\n'
' LongerLine 3 , None]], dtype=object)'
)
assert_equal(
np.array_repr(a, 20),
'array([[None,\n'
' Line 1\n'
' LooooooooooongestLine2\n'
' LongerLine 3 ],\n'
' [Line 1\n'
' LooooooooooongestLine2\n'
' LongerLine 3 ,\n'
' None]],\n'
' dtype=object)'
)
def test_nested_array_repr(self):
a = np.empty((2, 2), dtype=object)
a[0, 0] = np.eye(2)
a[0, 1] = np.eye(3)
a[1, 0] = None
a[1, 1] = np.ones((3, 1))
assert_equal(
repr(a),
'array([[array([[1., 0.],\n'
' [0., 1.]]), array([[1., 0., 0.],\n'
' [0., 1., 0.],\n'
' [0., 0., 1.]])],\n'
' [None, array([[1.],\n'
' [1.],\n'
' [1.]])]], dtype=object)'
)
@given(hynp.from_dtype(np.dtype("U")))
def test_any_text(self, text):
a = np.array([text, text, text])
assert_equal(a[0], text)
text = text.item()
expected_repr = "[{0!r} {0!r}\n {0!r}]".format(text)
result = np.array2string(a, max_line_width=len(repr(text)) * 2 + 3)
assert_equal(result, expected_repr)
@pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts")
def test_refcount(self):
gc.disable()
a = np.arange(2)
r1 = sys.getrefcount(a)
np.array2string(a)
np.array2string(a)
r2 = sys.getrefcount(a)
gc.collect()
gc.enable()
assert_(r1 == r2)
def test_with_sign(self):
a = np.array([-2, 0, 3])
assert_equal(
np.array2string(a, sign='+'),
'[-2 +0 +3]'
)
assert_equal(
np.array2string(a, sign='-'),
'[-2 0 3]'
)
assert_equal(
np.array2string(a, sign=' '),
'[-2 0 3]'
)
a = np.array([2, 0, 3])
assert_equal(
np.array2string(a, sign='+'),
'[+2 +0 +3]'
)
assert_equal(
np.array2string(a, sign='-'),
'[2 0 3]'
)
assert_equal(
np.array2string(a, sign=' '),
'[ 2 0 3]'
)
a = np.array([-2, -1, -3])
assert_equal(
np.array2string(a, sign='+'),
'[-2 -1 -3]'
)
assert_equal(
np.array2string(a, sign='-'),
'[-2 -1 -3]'
)
assert_equal(
np.array2string(a, sign=' '),
'[-2 -1 -3]'
)
a = np.array([[10, -1, 1, 1], [10, 10, 10, 10]])
assert_equal(
np.array2string(a, sign='+'),
'[[+10 -1 +1 +1]\n [+10 +10 +10 +10]]'
)
assert_equal(
np.array2string(a, sign='-'),
'[[10 -1 1 1]\n [10 10 10 10]]'
)
assert_equal(
np.array2string(a, sign=' '),
'[[10 -1 1 1]\n [10 10 10 10]]'
)
a = np.array([[10, 0, 1, 1], [10, 10, 10, 10]])
assert_equal(
np.array2string(a, sign='+'),
'[[+10 +0 +1 +1]\n [+10 +10 +10 +10]]'
)
assert_equal(
np.array2string(a, sign='-'),
'[[10 0 1 1]\n [10 10 10 10]]'
)
assert_equal(
np.array2string(a, sign=' '),
'[[ 10 0 1 1]\n [ 10 10 10 10]]'
)
a = np.array([[-10, -1, -1, -1], [-10, -10, -10, -10]])
assert_equal(
np.array2string(a, sign='+'),
'[[-10 -1 -1 -1]\n [-10 -10 -10 -10]]'
)
assert_equal(
np.array2string(a, sign='-'),
'[[-10 -1 -1 -1]\n [-10 -10 -10 -10]]'
)
assert_equal(
np.array2string(a, sign=' '),
'[[-10 -1 -1 -1]\n [-10 -10 -10 -10]]'
)
class TestPrintOptions:
"""Test getting and setting global print options."""
def setup_method(self):
self.oldopts = np.get_printoptions()
def teardown_method(self):
np.set_printoptions(**self.oldopts)
def test_basic(self):
x = np.array([1.5, 0, 1.234567890])
assert_equal(repr(x), "array([1.5 , 0. , 1.23456789])")
np.set_printoptions(precision=4)
assert_equal(repr(x), "array([1.5 , 0. , 1.2346])")
def test_precision_zero(self):
np.set_printoptions(precision=0)
for values, string in (
([0.], "0."), ([.3], "0."), ([-.3], "-0."), ([.7], "1."),
([1.5], "2."), ([-1.5], "-2."), ([-15.34], "-15."),
([100.], "100."), ([.2, -1, 122.51], " 0., -1., 123."),
([0], "0"), ([-12], "-12"), ([complex(.3, -.7)], "0.-1.j")):
x = np.array(values)
assert_equal(repr(x), "array([%s])" % string)
def test_formatter(self):
x = np.arange(3)
np.set_printoptions(formatter={'all': lambda x: str(x - 1)})
assert_equal(repr(x), "array([-1, 0, 1])")
def test_formatter_reset(self):
x = np.arange(3)
np.set_printoptions(formatter={'all': lambda x: str(x - 1)})
assert_equal(repr(x), "array([-1, 0, 1])")
np.set_printoptions(formatter={'int': None})
assert_equal(repr(x), "array([0, 1, 2])")
np.set_printoptions(formatter={'all': lambda x: str(x - 1)})
assert_equal(repr(x), "array([-1, 0, 1])")
np.set_printoptions(formatter={'all': None})
assert_equal(repr(x), "array([0, 1, 2])")
np.set_printoptions(formatter={'int': lambda x: str(x - 1)})
assert_equal(repr(x), "array([-1, 0, 1])")
np.set_printoptions(formatter={'int_kind': None})
assert_equal(repr(x), "array([0, 1, 2])")
x = np.arange(3.)
np.set_printoptions(formatter={'float': lambda x: str(x - 1)})
assert_equal(repr(x), "array([-1.0, 0.0, 1.0])")
np.set_printoptions(formatter={'float_kind': None})
assert_equal(repr(x), "array([0., 1., 2.])")
def test_override_repr(self):
x = np.arange(3)
np.set_printoptions(override_repr=lambda x: "FOO")
assert_equal(repr(x), "FOO")
np.set_printoptions(override_repr=None)
assert_equal(repr(x), "array([0, 1, 2])")
with np.printoptions(override_repr=lambda x: "BAR"):
assert_equal(repr(x), "BAR")
assert_equal(repr(x), "array([0, 1, 2])")
def test_0d_arrays(self):
assert_equal(str(np.array('café', '<U4')), 'café')
assert_equal(repr(np.array('café', '<U4')),
"array('café', dtype='<U4')")
assert_equal(str(np.array('test', np.str_)), 'test')
a = np.zeros(1, dtype=[('a', '<i4', (3,))])
assert_equal(str(a[0]), '([0, 0, 0],)')
assert_equal(repr(np.datetime64('2005-02-25')[...]),
"array('2005-02-25', dtype='datetime64[D]')")
assert_equal(repr(np.timedelta64('10', 'Y')[...]),
"array(10, dtype='timedelta64[Y]')")
x = np.array(1)
np.set_printoptions(formatter={'all':lambda x: "test"})
assert_equal(repr(x), "array(test)")
assert_equal(str(x), "1")
assert_warns(DeprecationWarning, np.array2string,
np.array(1.), style=repr)
np.array2string(np.array(1.), style=repr, legacy='1.13')
np.array2string(np.array(1.), legacy='1.13')
def test_float_spacing(self):
x = np.array([1., 2., 3.])
y = np.array([1., 2., -10.])
z = np.array([100., 2., -1.])
w = np.array([-100., 2., 1.])
assert_equal(repr(x), 'array([1., 2., 3.])')
assert_equal(repr(y), 'array([ 1., 2., -10.])')
assert_equal(repr(np.array(y[0])), 'array(1.)')
assert_equal(repr(np.array(y[-1])), 'array(-10.)')
assert_equal(repr(z), 'array([100., 2., -1.])')
assert_equal(repr(w), 'array([-100., 2., 1.])')
assert_equal(repr(np.array([np.nan, np.inf])), 'array([nan, inf])')
assert_equal(repr(np.array([np.nan, -np.inf])), 'array([ nan, -inf])')
x = np.array([np.inf, 100000, 1.1234])
y = np.array([np.inf, 100000, -1.1234])
z = np.array([np.inf, 1.1234, -1e120])
np.set_printoptions(precision=2)
assert_equal(repr(x), 'array([ inf, 1.00e+05, 1.12e+00])')
assert_equal(repr(y), 'array([ inf, 1.00e+05, -1.12e+00])')
assert_equal(repr(z), 'array([ inf, 1.12e+000, -1.00e+120])')
def test_bool_spacing(self):
assert_equal(repr(np.array([True, True])),
'array([ True, True])')
assert_equal(repr(np.array([True, False])),
'array([ True, False])')
assert_equal(repr(np.array([True])),
'array([ True])')
assert_equal(repr(np.array(True)),
'array(True)')
assert_equal(repr(np.array(False)),
'array(False)')
def test_sign_spacing(self):
a = np.arange(4.)
b = np.array([1.234e9])
c = np.array([1.0 + 1.0j, 1.123456789 + 1.123456789j], dtype='c16')
assert_equal(repr(a), 'array([0., 1., 2., 3.])')
assert_equal(repr(np.array(1.)), 'array(1.)')
assert_equal(repr(b), 'array([1.234e+09])')
assert_equal(repr(np.array([0.])), 'array([0.])')
assert_equal(repr(c),
"array([1. +1.j , 1.12345679+1.12345679j])")
assert_equal(repr(np.array([0., -0.])), 'array([ 0., -0.])')
np.set_printoptions(sign=' ')
assert_equal(repr(a), 'array([ 0., 1., 2., 3.])')
assert_equal(repr(np.array(1.)), 'array( 1.)')
assert_equal(repr(b), 'array([ 1.234e+09])')
assert_equal(repr(c),
"array([ 1. +1.j , 1.12345679+1.12345679j])")
assert_equal(repr(np.array([0., -0.])), 'array([ 0., -0.])')
np.set_printoptions(sign='+')
assert_equal(repr(a), 'array([+0., +1., +2., +3.])')
assert_equal(repr(np.array(1.)), 'array(+1.)')
assert_equal(repr(b), 'array([+1.234e+09])')
assert_equal(repr(c),
"array([+1. +1.j , +1.12345679+1.12345679j])")
np.set_printoptions(legacy='1.13')
assert_equal(repr(a), 'array([ 0., 1., 2., 3.])')
assert_equal(repr(b), 'array([ 1.23400000e+09])')
assert_equal(repr(-b), 'array([ -1.23400000e+09])')
assert_equal(repr(np.array(1.)), 'array(1.0)')
assert_equal(repr(np.array([0.])), 'array([ 0.])')
assert_equal(repr(c),
"array([ 1.00000000+1.j , 1.12345679+1.12345679j])")
assert_equal(str(np.array([-1., 10])), "[ -1. 10.]")
assert_raises(TypeError, np.set_printoptions, wrongarg=True)
def test_float_overflow_nowarn(self):
repr(np.array([1e4, 0.1], dtype='f2'))
def test_sign_spacing_structured(self):
a = np.ones(2, dtype='<f,<f')
assert_equal(repr(a),
"array([(1., 1.), (1., 1.)], dtype=[('f0', '<f4'), ('f1', '<f4')])")
assert_equal(repr(a[0]),
"np.void((1.0, 1.0), dtype=[('f0', '<f4'), ('f1', '<f4')])")
def test_legacy_mode_scalars(self):
np.set_printoptions(legacy='1.13')
assert_equal(str(np.float64(1.123456789123456789)), '1.12345678912')
assert_equal(str(np.complex128(complex(1, np.nan))), '(1+nan*j)')
np.set_printoptions(legacy=False)
assert_equal(str(np.float64(1.123456789123456789)),
'1.1234567891234568')
assert_equal(str(np.complex128(complex(1, np.nan))), '(1+nanj)')
@pytest.mark.parametrize(
['native'],
[
('bool',),
('uint8',),
('uint16',),
('uint32',),
('uint64',),
('int8',),
('int16',),
('int32',),
('int64',),
('float16',),
('float32',),
('float64',),
('U1',),
],
)
def test_dtype_endianness_repr(self, native):
'''
there was an issue where
repr(array([0], dtype='<u2')) and repr(array([0], dtype='>u2'))
both returned the same thing:
array([0], dtype=uint16)
even though their dtypes have different endianness.
'''
native_dtype = np.dtype(native)
non_native_dtype = native_dtype.newbyteorder()
non_native_repr = repr(np.array([1], non_native_dtype))
native_repr = repr(np.array([1], native_dtype))
assert ('dtype' in native_repr) ^ (native_dtype in _typelessdata),\
("an array's repr should show dtype if and only if the type "
'of the array is NOT one of the standard types '
'(e.g., int32, bool, float64).')
if non_native_dtype.itemsize > 1:
assert non_native_repr != native_repr
assert f"dtype='{non_native_dtype.byteorder}" in non_native_repr
def test_linewidth_repr(self):
a = np.full(7, fill_value=2)
np.set_printoptions(linewidth=17)
assert_equal(
repr(a),
textwrap.dedent("""\
array([2, 2, 2,
2, 2, 2,
2])""")
)
np.set_printoptions(linewidth=17, legacy='1.13')
assert_equal(
repr(a),
textwrap.dedent("""\
array([2, 2, 2,
2, 2, 2, 2])""")
)
a = np.full(8, fill_value=2)
np.set_printoptions(linewidth=18, legacy=False)
assert_equal(
repr(a),
textwrap.dedent("""\
array([2, 2, 2,
2, 2, 2,
2, 2])""")
)
np.set_printoptions(linewidth=18, legacy='1.13')
assert_equal(
repr(a),
textwrap.dedent("""\
array([2, 2, 2, 2,
2, 2, 2, 2])""")
)
def test_linewidth_str(self):
a = np.full(18, fill_value=2)
np.set_printoptions(linewidth=18)
assert_equal(
str(a),
textwrap.dedent("""\
[2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2
2 2]""")
)
np.set_printoptions(linewidth=18, legacy='1.13')
assert_equal(
str(a),
textwrap.dedent("""\
[2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2]""")
)
def test_edgeitems(self):
np.set_printoptions(edgeitems=1, threshold=1)
a = np.arange(27).reshape((3, 3, 3))
assert_equal(
repr(a),
textwrap.dedent("""\
array([[[ 0, ..., 2],
...,
[ 6, ..., 8]],
...,
[[18, ..., 20],
...,
[24, ..., 26]]])""")
)
b = np.zeros((3, 3, 1, 1))
assert_equal(
repr(b),
textwrap.dedent("""\
array([[[[0.]],
...,
[[0.]]],
...,
[[[0.]],
...,
[[0.]]]])""")
)
np.set_printoptions(legacy='1.13')
assert_equal(
repr(a),
textwrap.dedent("""\
array([[[ 0, ..., 2],
...,
[ 6, ..., 8]],
...,
[[18, ..., 20],
...,
[24, ..., 26]]])""")
)
assert_equal(
repr(b),
textwrap.dedent("""\
array([[[[ 0.]],
...,
[[ 0.]]],
...,
[[[ 0.]],
...,
[[ 0.]]]])""")
)
def test_edgeitems_structured(self):
np.set_printoptions(edgeitems=1, threshold=1)
A = np.arange(5*2*3, dtype="<i8").view([('i', "<i8", (5, 2, 3))])
reprA = (
"array([([[[ 0, ..., 2], [ 3, ..., 5]], ..., "
"[[24, ..., 26], [27, ..., 29]]],)],\n"
" dtype=[('i', '<i8', (5, 2, 3))])"
)
assert_equal(repr(A), reprA)
def test_bad_args(self):
assert_raises(ValueError, np.set_printoptions, threshold=float('nan'))
assert_raises(TypeError, np.set_printoptions, threshold='1')
assert_raises(TypeError, np.set_printoptions, threshold=b'1')
assert_raises(TypeError, np.set_printoptions, precision='1')
assert_raises(TypeError, np.set_printoptions, precision=1.5)
def test_unicode_object_array():
expected = "array(['é'], dtype=object)"
x = np.array(['\xe9'], dtype=object)
assert_equal(repr(x), expected)
class TestContextManager:
def test_ctx_mgr(self):
with np.printoptions(precision=2):
s = str(np.array([2.0]) / 3)
assert_equal(s, '[0.67]')
def test_ctx_mgr_restores(self):
opts = np.get_printoptions()
with np.printoptions(precision=opts['precision'] - 1,
linewidth=opts['linewidth'] - 4):
pass
assert_equal(np.get_printoptions(), opts)
def test_ctx_mgr_exceptions(self):
opts = np.get_printoptions()
try:
with np.printoptions(precision=2, linewidth=11):
raise ValueError
except ValueError:
pass
assert_equal(np.get_printoptions(), opts)
def test_ctx_mgr_as_smth(self):
opts = {"precision": 2}
with np.printoptions(**opts) as ctx:
saved_opts = ctx.copy()
assert_equal({k: saved_opts[k] for k in opts}, opts)
@pytest.mark.parametrize("dtype", "bhilqpBHILQPefdgFDG")
@pytest.mark.parametrize("value", [0, 1])
def test_scalar_repr_numbers(dtype, value):
dtype = np.dtype(dtype)
scalar = np.array(value, dtype=dtype)[()]
assert isinstance(scalar, np.generic)
string = str(scalar)
repr_string = string.strip("()")
representation = repr(scalar)
if dtype.char == "g":
assert representation == f"np.longdouble('{repr_string}')"
elif dtype.char == 'G':
assert representation == f"np.clongdouble('{repr_string}')"
else:
normalized_name = np.dtype(f"{dtype.kind}{dtype.itemsize}").type.__name__
assert representation == f"np.{normalized_name}({repr_string})"
with np.printoptions(legacy="1.25"):
assert repr(scalar) == string
@pytest.mark.parametrize("scalar, legacy_repr, representation", [
(np.True_, "True", "np.True_"),
(np.bytes_(b'a'), "b'a'", "np.bytes_(b'a')"),
(np.str_('a'), "'a'", "np.str_('a')"),
(np.datetime64("2012"),
"numpy.datetime64('2012')", "np.datetime64('2012')"),
(np.timedelta64(1), "numpy.timedelta64(1)", "np.timedelta64(1)"),
(np.void((True, 2), dtype="?,<i8"),
"(True, 2)",
"np.void((True, 2), dtype=[('f0', '?'), ('f1', '<i8')])"),
(np.void((1, 2), dtype="<f8,>f4"),
"(1., 2.)",
"np.void((1.0, 2.0), dtype=[('f0', '<f8'), ('f1', '>f4')])"),
(np.void(b'a'), r"void(b'\x61')", r"np.void(b'\x61')"),
])
def test_scalar_repr_special(scalar, legacy_repr, representation):
assert repr(scalar) == representation
with np.printoptions(legacy="1.25"):
assert repr(scalar) == legacy_repr
def test_scalar_void_float_str():
scalar = np.void((1.0, 2.0), dtype=[('f0', '<f8'), ('f1', '>f4')])
assert str(scalar) == "(1.0, 2.0)"