NumPy-1-26-中文文档-十九-

NumPy 1.26 中文文档(十九)

原文:numpy.org/doc/

支持测试覆盖(numpy.testing.overrides

原文:numpy.org/doc/1.26/reference/routines.testing.overrides.html

支持测试自定义数组容器实现。

实用函数

allows_array_function_override(func) 确定一个 Numpy 函数是否可以通过array_function覆盖
allows_array_ufunc_override(func) 确定一个函数是否可以通过array_ufunc覆盖
get_overridable_numpy_ufuncs() 列出所有可以通过array_ufunc覆盖的 numpy ufuncs
get_overridable_numpy_array_functions() 列出所有可以通过array_function覆盖的 numpy 函数

实用函数

allows_array_function_override(func) 确定一个 Numpy 函数是否可以通过array_function覆盖
allows_array_ufunc_override(func) 确定一个函数是否可以通过array_ufunc覆盖
get_overridable_numpy_ufuncs() 列出所有可以通过array_ufunc覆盖的 numpy ufuncs
get_overridable_numpy_array_functions() 列出所有可以通过array_function覆盖的 numpy 函数

numpy.testing.overrides.allows_array_function_override

原文:numpy.org/doc/1.26/reference/generated/numpy.testing.overrides.allows_array_function_override.html

testing.overrides.allows_array_function_override(func)

确定一个 NumPy 函数是否可以通过array_function进行重写

参数:

funccallable

一个可能可以通过array_function进行重写的函数

返回:

布尔值

如果func是可以通过array_function进行重写的 NumPy API 中的函数,则返回True,否则返回False

numpy.testing.overrides.allows_array_ufunc_override

原文:numpy.org/doc/1.26/reference/generated/numpy.testing.overrides.allows_array_ufunc_override.html

testing.overrides.allows_array_ufunc_override(func)

确定一个函数是否可以通过 array_ufunc 被覆盖。

参数:

func可调用的

可能可以通过 array_ufunc 被覆盖的函数。

返回:

布尔

True 如果 func 可以通过 array_ufunc 覆盖,否则为 False

注意

这个函数等同于 isinstance(func, np.ufunc),并且对于在 Numpy 之外定义的 ufuncs 也能够正常工作。

numpy.testing.overrides.get_overridable_numpy_ufuncs

原文:numpy.org/doc/1.26/reference/generated/numpy.testing.overrides.get_overridable_numpy_ufuncs.html

testing.overrides.get_overridable_numpy_ufuncs()

列出所有可以通过array_ufunc重写的 numpy ufunc。

参数:

None

返回值:

set

包含所有可以重写的公共 numpy API 中的 ufunc 的集合。

numpy.testing.overrides.get_overridable_numpy_array_functions

原文:numpy.org/doc/1.26/reference/generated/numpy.testing.overrides.get_overridable_numpy_array_functions.html

testing.overrides.get_overridable_numpy_array_functions()

列出所有可以通过array_function进行覆盖的 numpy 函数

参数:

None

返回:

set

包含所有可以通过array_function进行覆盖的公共 numpy API 函数的集合。

窗口函数

原文:numpy.org/doc/1.26/reference/routines.window.html

各种窗口函数

bartlett(M) 返回巴特莱特窗口。
blackman(M) 返回布莱克曼窗口。
hamming(M) 返回海明窗口。
hanning(M) 返回汉宁窗口。
kaiser(M, beta) 返回卡泽窗口。

各种窗口函数

bartlett(M) 返回巴特莱特窗口。
blackman(M) 返回布莱克曼窗口。
hamming(M) 返回海明窗口。
hanning(M) 返回汉宁窗口。
kaiser(M, beta) 返回卡泽窗口。

numpy.bartlett

原文:numpy.org/doc/1.26/reference/generated/numpy.bartlett.html

numpy.bartlett(M)

返回巴特勒窗口。

巴特勒窗口与三角窗口非常相似,只是端点为零。它经常在信号处理中用于锐化信号,而在频率域中不会产生太多的纹波。

参数:

M整数

输出窗口中的点数。如果小于或等于零,则返回空数组。

返回:

out数组

三角形窗口,最大值归一化为一(仅当样本数为奇数时才出现),第一个和最后一个样本等于零。

另请参阅

blackman, hamming, hanning, kaiser

注意

巴特勒窗口定义为

[w(n) = \frac{2}{M-1} \left( \frac{M-1}{2} - \left|n - \frac{M-1}{2}\right| \right)]

大多数关于巴特勒窗口的参考来源于信号处理文献,其中它被用作许多窗函数之一,用于平滑值。请注意,与此窗口的卷积会产生线性插值。它也被称为斜顶函数(即“去除足”,即平滑采样信号起止点的不连续性)或抑制函数。巴特勒窗口的傅立叶变换是两个 sinc 函数的乘积。请注意 Kanasewich [2]中的出色讨论。

参考文献

[1]

M.S. Bartlett,《周期图分析和连续谱》,Biometrika 37,1-16,1950 年。

[2]

E.R. Kanasewich,《地球物理学时间序列分析》,亚伯达大学出版社,1975 年,第 109-110 页。

[3]

A.V. Oppenheim and R.W. Schafer,《离散时间信号处理》,Prentice-Hall,1999 年,第 468-471 页。

[4]

维基百科,《窗函数》,en.wikipedia.org/wiki/Window_function

[5]

W.H. Press, B.P. Flannery, S.A. Teukolsky, and W.T. Vetterling,《数值配方》,剑桥大学出版社,1986 年,第 429 页。

示例

>>> import matplotlib.pyplot as plt
>>> np.bartlett(12)
array([ 0\.        ,  0.18181818,  0.36363636,  0.54545455,  0.72727273, # may vary
 0.90909091,  0.90909091,  0.72727273,  0.54545455,  0.36363636,
 0.18181818,  0\.        ]) 

绘制窗口及其频率响应(需要 SciPy 和 matplotlib):

>>> from numpy.fft import fft, fftshift
>>> window = np.bartlett(51)
>>> plt.plot(window)
[<matplotlib.lines.Line2D object at 0x...>]
>>> plt.title("Bartlett window")
Text(0.5, 1.0, 'Bartlett window')
>>> plt.ylabel("Amplitude")
Text(0, 0.5, 'Amplitude')
>>> plt.xlabel("Sample")
Text(0.5, 0, 'Sample')
>>> plt.show() 

../../_images/numpy-bartlett-1_00_00.png

>>> plt.figure()
<Figure size 640x480 with 0 Axes>
>>> A = fft(window, 2048) / 25.5
>>> mag = np.abs(fftshift(A))
>>> freq = np.linspace(-0.5, 0.5, len(A))
>>> with np.errstate(divide='ignore', invalid='ignore'):
...     response = 20 * np.log10(mag)
...
>>> response = np.clip(response, -100, 100)
>>> plt.plot(freq, response)
[<matplotlib.lines.Line2D object at 0x...>]
>>> plt.title("Frequency response of Bartlett window")
Text(0.5, 1.0, 'Frequency response of Bartlett window')
>>> plt.ylabel("Magnitude [dB]")
Text(0, 0.5, 'Magnitude [dB]')
>>> plt.xlabel("Normalized frequency [cycles per sample]")
Text(0.5, 0, 'Normalized frequency [cycles per sample]')
>>> _ = plt.axis('tight')
>>> plt.show() 

../../_images/numpy-bartlett-1_01_00.png

numpy.blackman

原文:numpy.org/doc/1.26/reference/generated/numpy.blackman.html

numpy.blackman(M)

返回 Blackman 窗口。

Blackman 窗口是通过使用余弦的前三项的总和形成的锥形窗口。它被设计为具有尽可能小的泄漏。它接近于最佳,只比 Kaiser 窗口略差一点。

参数:

Mint

输出窗口的点数。如果为零或小于零,则返回一个空数组。

返回:

outndarray

此窗口的最大值被标准化为 1(仅当样本数为奇数时才出现值为 1)。

另见

bartlett, hamming, hanning, kaiser

笔记

Blackman 窗口定义为

[w(n) = 0.42 - 0.5 \cos(2\pi n/M) + 0.08 \cos(4\pi n/M)]

大多数关于 Blackman 窗口的引用来自信号处理文献中,用作许多用于平滑值的窗口函数之一。它也被称为消足(即“去除脚”,即平滑采样信号开头和结尾的不连续性)函数或锥形函数。它被认为是一种“近乎最佳”的锥形函数,按某些标准几乎和 Kaiser 窗口一样好。

参考文献

Blackman, R.B. 和 Tukey, J.W., (1958) The measurement of power spectra, Dover Publications, New York.

Oppenheim, A.V., 和 R.W. Schafer. Discrete-Time Signal Processing. Upper Saddle River, NJ: Prentice-Hall, 1999, pp. 468-471.

示例

>>> import matplotlib.pyplot as plt
>>> np.blackman(12)
array([-1.38777878e-17,   3.26064346e-02,   1.59903635e-01, # may vary
 4.14397981e-01,   7.36045180e-01,   9.67046769e-01,
 9.67046769e-01,   7.36045180e-01,   4.14397981e-01,
 1.59903635e-01,   3.26064346e-02,  -1.38777878e-17]) 

绘制窗口和频率响应:

>>> from numpy.fft import fft, fftshift
>>> window = np.blackman(51)
>>> plt.plot(window)
[<matplotlib.lines.Line2D object at 0x...>]
>>> plt.title("Blackman window")
Text(0.5, 1.0, 'Blackman window')
>>> plt.ylabel("Amplitude")
Text(0, 0.5, 'Amplitude')
>>> plt.xlabel("Sample")
Text(0.5, 0, 'Sample')
>>> plt.show() 

../../_images/numpy-blackman-1_00_00.png

>>> plt.figure()
<Figure size 640x480 with 0 Axes>
>>> A = fft(window, 2048) / 25.5
>>> mag = np.abs(fftshift(A))
>>> freq = np.linspace(-0.5, 0.5, len(A))
>>> with np.errstate(divide='ignore', invalid='ignore'):
...     response = 20 * np.log10(mag)
...
>>> response = np.clip(response, -100, 100)
>>> plt.plot(freq, response)
[<matplotlib.lines.Line2D object at 0x...>]
>>> plt.title("Frequency response of Blackman window")
Text(0.5, 1.0, 'Frequency response of Blackman window')
>>> plt.ylabel("Magnitude [dB]")
Text(0, 0.5, 'Magnitude [dB]')
>>> plt.xlabel("Normalized frequency [cycles per sample]")
Text(0.5, 0, 'Normalized frequency [cycles per sample]')
>>> _ = plt.axis('tight')
>>> plt.show() 

../../_images/numpy-blackman-1_01_00.png

numpy.hamming

原文:numpy.org/doc/1.26/reference/generated/numpy.hamming.html

numpy.hamming(M)

返回 Hamming 窗口。

Hamming 窗口是通过使用加权余弦形成的锥形。

参数:

Mint

输出窗口中的点数。如果为零或小于零,则返回一个空数组。

返回:

out数组

窗口,其最大值归一化为一(仅当样本数量为奇数时才出现值为一)。

另请参阅

bartlett, blackman, hanning, kaiser

注意事项

Hamming 窗口定义为

[w(n) = 0.54 - 0.46\cos\left(\frac{2\pi{n}}{M-1}\right) \qquad 0 \leq n \leq M-1]

Hamming 窗口是以 R. W. Hamming 的名字命名的,他是 J. W. Tukey 的合作者,并在 Blackman 和 Tukey 的著作中有描述。建议用于平滑时域中截断自相关函数。对 Hamming 窗口的大多数引用来自信号处理文献,其中它被用作众多窗函数之一,用于平滑数值。它也被称为 apodization(意思是“去除脚部”,即平滑采样信号开头和结尾的不连续性)或锥形函数。

参考文献

[1]

Blackman, R.B. 和 Tukey, J.W., (1958)《功率谱的测量》,多佛出版社,纽约。

[2]

E.R. Kanasewich,“地球物理中的时间序列分析”,阿尔伯塔大学出版社,1975 年,第 109-110 页。

[3]

维基百科,“窗函数”,zh.wikipedia.org/wiki/窗函数

[4]

W.H. Press, B.P. Flannery, S.A. Teukolsky 和 W.T. Vetterling,“数值计算方法”,剑桥大学出版社,1986 年,第 425 页。

示例

>>> np.hamming(12)
array([ 0.08      ,  0.15302337,  0.34890909,  0.60546483,  0.84123594, # may vary
 0.98136677,  0.98136677,  0.84123594,  0.60546483,  0.34890909,
 0.15302337,  0.08      ]) 

绘制窗口和频率响应:

>>> import matplotlib.pyplot as plt
>>> from numpy.fft import fft, fftshift
>>> window = np.hamming(51)
>>> plt.plot(window)
[<matplotlib.lines.Line2D object at 0x...>]
>>> plt.title("Hamming window")
Text(0.5, 1.0, 'Hamming window')
>>> plt.ylabel("Amplitude")
Text(0, 0.5, 'Amplitude')
>>> plt.xlabel("Sample")
Text(0.5, 0, 'Sample')
>>> plt.show() 

../../_images/numpy-hamming-1_00_00.png

>>> plt.figure()
<Figure size 640x480 with 0 Axes>
>>> A = fft(window, 2048) / 25.5
>>> mag = np.abs(fftshift(A))
>>> freq = np.linspace(-0.5, 0.5, len(A))
>>> response = 20 * np.log10(mag)
>>> response = np.clip(response, -100, 100)
>>> plt.plot(freq, response)
[<matplotlib.lines.Line2D object at 0x...>]
>>> plt.title("Frequency response of Hamming window")
Text(0.5, 1.0, 'Frequency response of Hamming window')
>>> plt.ylabel("Magnitude [dB]")
Text(0, 0.5, 'Magnitude [dB]')
>>> plt.xlabel("Normalized frequency [cycles per sample]")
Text(0.5, 0, 'Normalized frequency [cycles per sample]')
>>> plt.axis('tight')
...
>>> plt.show() 

../../_images/numpy-hamming-1_01_00.png

numpy.hanning

原文:numpy.org/doc/1.26/reference/generated/numpy.hanning.html

numpy.hanning(M)

返回汉宁窗口。

汉宁窗口是通过使用加权余弦形成的锥形。

参数:

M整型

输出窗口中的点数。如果为零或更少,则返回一个空数组。

返回值:

out数组,形状(M,)

窗口,最大值归一化为一(仅当 M 为奇数时出现值一)。

也请参阅

bartlettblackmanhammingkaiser

注释

汉宁窗口的定义为

[w(n) = 0.5 - 0.5\cos\left(\frac{2\pi{n}}{M-1}\right) \qquad 0 \leq n \leq M-1]

汉宁窗是以奥地利气象学家尤利乌斯·汉尼(Julius von Hann)的名字命名的。它也被称为余弦钟。一些作者更喜欢将其称为汉宁窗口,以避免与非常相似的哈明窗口混淆。

汉宁窗口的大多数参考文献来自信号处理文献,它被用作许多平滑数值的窗口函数之一。它也被称为加权削波(即“去除基座”,即使采样信号的开始和结束处的不连续性平滑)或锥形函数。

参考文献

[1]

Blackman,R.B.和 Tukey,J.W.,(1958)功率谱的测量,多佛出版社,纽约。

[2]

E.R. Kanasewich,“地球物理学中的时间序列分析”,阿尔伯塔大学出版社,1975 年,第 106-108 页。

[3]

维基百科,“窗口函数”,en.wikipedia.org/wiki/Window_function

[4]

W.H. Press, B.P. Flannery, S.A. Teukolsky, and W.T. Vetterling,“数值算法”,剑桥大学出版社,1986 年,第 425 页。

示例

>>> np.hanning(12)
array([0\.        , 0.07937323, 0.29229249, 0.57115742, 0.82743037,
 0.97974649, 0.97974649, 0.82743037, 0.57115742, 0.29229249,
 0.07937323, 0\.        ]) 

绘制窗口及其频率响应:

>>> import matplotlib.pyplot as plt
>>> from numpy.fft import fft, fftshift
>>> window = np.hanning(51)
>>> plt.plot(window)
[<matplotlib.lines.Line2D object at 0x...>]
>>> plt.title("Hann window")
Text(0.5, 1.0, 'Hann window')
>>> plt.ylabel("Amplitude")
Text(0, 0.5, 'Amplitude')
>>> plt.xlabel("Sample")
Text(0.5, 0, 'Sample')
>>> plt.show() 

../../_images/numpy-hanning-1_00_00.png

>>> plt.figure()
<Figure size 640x480 with 0 Axes>
>>> A = fft(window, 2048) / 25.5
>>> mag = np.abs(fftshift(A))
>>> freq = np.linspace(-0.5, 0.5, len(A))
>>> with np.errstate(divide='ignore', invalid='ignore'):
...     response = 20 * np.log10(mag)
...
>>> response = np.clip(response, -100, 100)
>>> plt.plot(freq, response)
[<matplotlib.lines.Line2D object at 0x...>]
>>> plt.title("Frequency response of the Hann window")
Text(0.5, 1.0, 'Frequency response of the Hann window')
>>> plt.ylabel("Magnitude [dB]")
Text(0, 0.5, 'Magnitude [dB]')
>>> plt.xlabel("Normalized frequency [cycles per sample]")
Text(0.5, 0, 'Normalized frequency [cycles per sample]')
>>> plt.axis('tight')
...
>>> plt.show() 

../../_images/numpy-hanning-1_01_00.png

numpy.kaiser

原文:numpy.org/doc/1.26/reference/generated/numpy.kaiser.html

numpy.kaiser(M, beta)

返回 Kaiser 窗口。

Kaiser 窗口是通过使用贝塞尔函数形成的锥形。

参数:

Mint

输出窗口中的点数。如果为零或更少,则返回一个空数组。

betafloat

窗口的形状参数。

返回:

outarray

窗口,最大值归一化为一(仅当样本数为奇数时才出现值为一)。

参见

bartlett, blackman, hamming, hanning

注释

Kaiser 窗口定义为

[w(n) = I_0\left( \beta \sqrt{1-\frac{4n²}{(M-1)²}} \right)/I_0(\beta)]

具有

[\quad -\frac{M-1}{2} \leq n \leq \frac{M-1}{2},]

其中 (I_0) 是修改后的零阶贝塞尔函数。

Kaiser 窗口以 Jim Kaiser 命名,他发现了基于贝塞尔函数的 DPSS 窗口的简单近似。Kaiser 窗口是对数字椭球序列(Digital Prolate Spheroidal Sequence,或 Slepian 窗口)的一个非常好的近似,该序列最大化了窗口主瓣中的能量相对于总能量。

Kaiser 可通过改变 beta 参数来近似许多其他窗口。

beta 窗口形状
0 矩形
5 类似于 Hamming
6 类似于 Hanning
8.6 类似于 Blackman

beta 值为 14 可能是一个很好的起点。请注意,随着 beta 值变大,窗口变窄,因此样本数量需要足够大以对越来越窄的尖峰进行采样,否则会返回 NaN。

大多数关于 Kaiser 窗口的参考资料来自信号处理文献,它被用作许多窗口函数之一,用于平滑值。它也被称为消足(即“去除脚部”,即平滑采样信号开头和结尾的不连续性)或锥形函数。

参考文献

[1]

J. F. Kaiser,“数字滤波器” - “数字计算机系统分析”第七章,编辑:F.F. Kuo 和 J.F. Kaiser,第 218-285 页。约翰·威利和儿子,纽约,(1966)。

[2]

E.R. Kanasewich,“地球物理中的时间序列分析”,阿尔伯塔大学出版社,1975 年,第 177-178 页。

[3]

维基百科,“窗口函数”,en.wikipedia.org/wiki/Window_function

示例

>>> import matplotlib.pyplot as plt
>>> np.kaiser(12, 14)
 array([7.72686684e-06, 3.46009194e-03, 4.65200189e-02, # may vary
 2.29737120e-01, 5.99885316e-01, 9.45674898e-01,
 9.45674898e-01, 5.99885316e-01, 2.29737120e-01,
 4.65200189e-02, 3.46009194e-03, 7.72686684e-06]) 

绘制窗口和频率响应:

>>> from numpy.fft import fft, fftshift
>>> window = np.kaiser(51, 14)
>>> plt.plot(window)
[<matplotlib.lines.Line2D object at 0x...>]
>>> plt.title("Kaiser window")
Text(0.5, 1.0, 'Kaiser window')
>>> plt.ylabel("Amplitude")
Text(0, 0.5, 'Amplitude')
>>> plt.xlabel("Sample")
Text(0.5, 0, 'Sample')
>>> plt.show() 

../../_images/numpy-kaiser-1_00_00.png

>>> plt.figure()
<Figure size 640x480 with 0 Axes>
>>> A = fft(window, 2048) / 25.5
>>> mag = np.abs(fftshift(A))
>>> freq = np.linspace(-0.5, 0.5, len(A))
>>> response = 20 * np.log10(mag)
>>> response = np.clip(response, -100, 100)
>>> plt.plot(freq, response)
[<matplotlib.lines.Line2D object at 0x...>]
>>> plt.title("Frequency response of Kaiser window")
Text(0.5, 1.0, 'Frequency response of Kaiser window')
>>> plt.ylabel("Magnitude [dB]")
Text(0, 0.5, 'Magnitude [dB]')
>>> plt.xlabel("Normalized frequency [cycles per sample]")
Text(0.5, 0, 'Normalized frequency [cycles per sample]')
>>> plt.axis('tight')
(-0.5, 0.5, -100.0, ...) # may vary
>>> plt.show() 

../../_images/numpy-kaiser-1_01_00.png

类型(numpy.typing

原文:numpy.org/doc/1.26/reference/typing.html

1.20 版本中的新功能。

NumPy API 的大部分内容采用了PEP 484风格的类型注解。此外,用户还可以使用一些类型别名,其中两个最重要的如下:

  • ArrayLike:可以转换为数组的对象

  • DTypeLike:可以转换为数据类型的对象

Mypy 插件

1.21 版本中的新功能。

一个mypy插件,用于管理一系列特定于平台的注解。它的功能可以分为三个不同的部分:

  • 分配某些number子类的(依赖于平台)精度,包括int_intplonglong等。查看标量类型的文档,了解受影响类的全面概述。如果没有插件,所有相关类的精度将被推断为Any

  • 移除在特定平台上不可用的所有扩展精度number子类。其中最显著的包括float128complex256等。如果没有插件,则在 mypy 的视角下,所有扩展精度类型都将对所有平台可用。

  • 分配c_intp的(依赖于平台)精度。如果没有插件,类型将默认为ctypes.c_int64

    1.22 版本中的新功能。

示例

要启用插件,必须将其添加到自己的 mypy 配置文件中:

[mypy]
plugins  =  numpy.typing.mypy_plugin 

与运行时 NumPy API 的差异

NumPy 非常灵活。试图静态描述所有可能性将导致类型不太有用。因此,有时候,有类型的 NumPy API 通常比运行时 NumPy API 更严格。本节描述了一些显著差异。

ArrayLike

ArrayLike类型试图避免创建对象数组。例如,

>>> np.array(x**2 for x in range(10))
array(<generator object <genexpr> at ...>, dtype=object) 

是有效的 NumPy 代码,将创建一个零维对象数组。然而,如果使用 NumPy 类型,类型检查器将会对上述示例提出异议。如果您确实打算执行上述操作,那么可以使用# type: ignore注释:

>>> np.array(x**2 for x in range(10))  # type: ignore 

或者明确将类似数组对象类型定义为Any:

>>> from typing import Any
>>> array_like: Any = (x**2 for x in range(10))
>>> np.array(array_like)
array(<generator object <genexpr> at ...>, dtype=object) 

ndarray

可以在运行时改变数组的数据类型。例如,以下代码是有效的:

>>> x = np.array([1, 2])
>>> x.dtype = np.bool_ 

类型检查器不允许此类变异。想要编写静态类型代码的用户应该使用numpy.ndarray.view方法,用不同的 dtype 创建数组的视图。

DTypeLike

DTypeLike 类型试图避免使用字段字典创建 dtype 对象,如下所示:

>>> x = np.dtype({"field1": (float, 1), "field2": (int, 3)}) 

尽管这是有效的 NumPy 代码,但类型检查器会对此提出抱怨,因为不鼓励使用它。请参见:数据类型对象

数字精度

numpy.number子类的精度被视为协变泛型参数(见NBitBase),简化了涉及基于精度的转换的注释过程。

>>> from typing import TypeVar
>>> import numpy as np
>>> import numpy.typing as npt

>>> T = TypeVar("T", bound=npt.NBitBase)
>>> def func(a: "np.floating[T]", b: "np.floating[T]") -> "np.floating[T]":
...     ... 

因此,float16float32float64仍然是floating的子类型,但与运行时相反,它们未必被视为子类。

Timedelta64

timedelta64 类在静态类型检查时不被视为signedinteger的子类,它只从generic继承。

0 维数组

在运行时,numpy 会将任何传递进来的 0 维数组积极地转换为相应的generic实例。在引入形状类型(参见PEP 646)之前,很遗憾目前无法进行必要的区分 0D 和> 0D 数组。因此,尽管不严格正确,所有可能执行 0 维数组->标量转换的操作都目前被标注为只返回ndarray

如果事先知道某个操作将执行 0 维数组->标量的转换,那么可以考虑使用typing.cast# type: ignore注释手动解决该问题。

记录数组数据类型

numpy.recarray的数据类型,以及一般情况下的numpy.rec函数,可以通过以下两种方式之一指定:

  • 通过dtype参数直接指定。

  • 具有通过 numpy.format_parser 操作的最多五个辅助参数:formatsnamestitlesalignedbyteorder

目前这两种方法被标记为互斥, 如果指定了 dtype,则不能指定 formats。虽然这种互斥性在运行时不是(严格)强制执行的,但结合两种 dtype 指定符可能会导致意外或甚至明显错误的行为。

API

numpy.typing.ArrayLike = typing.Union[...]

代表可以强制转换为 ndarray 的对象的 Union

其中包括但不限于:

  • 标量。

  • (嵌套的)序列。

  • 实现 array 协议的对象。

新版本 1.20 中新增。

参见

array_like:

任何可解释为 ndarray 的标量或序列。

示例

>>> import numpy as np
>>> import numpy.typing as npt

>>> def as_array(a: npt.ArrayLike) -> np.ndarray:
...     return np.array(a) 
numpy.typing.DTypeLike = typing.Union[...]

代表可以强制转换为 dtype 的对象的 Union

其中包括但不限于:

  • type 对象。

  • 字符代码或 type 对象的名称。

  • 具有 .dtype 属性的对象。

新版本 1.20 中新增。

参见

指定和构造数据类型

所有可以强制转换为数据类型的对象的全面概述。

示例

>>> import numpy as np
>>> import numpy.typing as npt

>>> def as_dtype(d: npt.DTypeLike) -> np.dtype:
...     return np.dtype(d) 
numpy.typing.NDArray = numpy.ndarray[typing.Any, numpy.dtype[+_ScalarType_co]]

np.ndarray[Any, np.dtype[+ScalarType]]通用 版本。

可在运行时用于为具有给定 dtype 和未指定形状的数组进行类型标注。

新版本 1.21 中新增。

示例

>>> import numpy as np
>>> import numpy.typing as npt

>>> print(npt.NDArray)
numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]]

>>> print(npt.NDArray[np.float64])
numpy.ndarray[typing.Any, numpy.dtype[numpy.float64]]

>>> NDArrayInt = npt.NDArray[np.int_]
>>> a: NDArrayInt = np.arange(10)

>>> def func(a: npt.ArrayLike) -> npt.NDArray[Any]:
...     return np.array(a) 
class numpy.typing.NBitBase

代表 numpy.number 精度的类型在静态类型检查期间。

专门用于静态类型检查目的,NBitBase 代表一个层次化子类集合的基类。每个后续子类用于表示更低级别的精度,例如 64Bit > 32Bit > 16Bit

新版本 1.20 中新增。

示例

下面是一个典型的使用示例:NBitBase 用于为接受任意精度的浮点数和整数作为参数并返回精度较大的新浮点数的函数进行注释(例如 np.float16 + np.int64 -> np.float64)。

>>> from __future__ import annotations
>>> from typing import TypeVar, TYPE_CHECKING
>>> import numpy as np
>>> import numpy.typing as npt

>>> T1 = TypeVar("T1", bound=npt.NBitBase)
>>> T2 = TypeVar("T2", bound=npt.NBitBase)

>>> def add(a: np.floating[T1], b: np.integer[T2]) -> np.floating[T1 | T2]:
...     return a + b

>>> a = np.float16()
>>> b = np.int64()
>>> out = add(a, b)

>>> if TYPE_CHECKING:
...     reveal_locals()
...     # note: Revealed local types are:
...     # note:     a: numpy.floating[numpy.typing._16Bit*]
...     # note:     b: numpy.signedinteger[numpy.typing._64Bit*]
...     # note:     out: numpy.floating[numpy.typing._64Bit*] 

Mypy 插件

新版本 1.21 中新增。

用于管理一些特定平台注释的 mypy 插件。其功能可以分为三个明确的部分:

  • 分配了某些number子类的(平台相关)精度,包括int_intplonglong的精度。有关受影响类的综合概述,请参阅标量类型的文档。没有使用插件,所有相关类的精度将被推断为Any

  • 删除在特定平台上不可用的所有扩展精度的number子类。最显著的包括float128complex256。如果不使用插件,所有扩展精度类型在 mypy 看来都对所有平台可用。

  • 分配c_intp的(平台相关)精度。没有使用插件,类型将默认为ctypes.c_int64

    版本 1.22 中的新功能。

示例

要启用该插件,必须将其添加到 mypy 的配置文件中:

[mypy]
plugins  =  numpy.typing.mypy_plugin 

示例

要启用该插件,必须将其添加到 mypy 的配置文件中:

[mypy]
plugins  =  numpy.typing.mypy_plugin 

与运行时 NumPy API 的差异

NumPy 非常灵活。试图静态描述所有可能性将导致不太有帮助的类型。因此,类型化 NumPy API 往往比运行时 NumPy API 严格。本节描述了一些值得注意的差异。

ArrayLike

ArrayLike类型尝试避免创建对象数组。例如,

>>> np.array(x**2 for x in range(10))
array(<generator object <genexpr> at ...>, dtype=object) 

这是有效的 NumPy 代码,将创建一个 0 维对象数组。然而,当使用 NumPy 类型时,类型检查器会对上述示例提出抱怨。如果您真的打算执行上述操作,那么您可以使用# type: ignore注释:

>>> np.array(x**2 for x in range(10))  # type: ignore 

或者将数组对象明确类型为Any:

>>> from typing import Any
>>> array_like: Any = (x**2 for x in range(10))
>>> np.array(array_like)
array(<generator object <genexpr> at ...>, dtype=object) 

ndarray

数组的数据类型可以在运行时进行变异。例如,以下代码是有效的:

>>> x = np.array([1, 2])
>>> x.dtype = np.bool_ 

类型不允许此类变异。希望编写静态类型代码的用户应该使用numpy.ndarray.view方法,以创建具有不同数据类型的数组视图。

DTypeLike

DTypeLike 类型试图避免像下面这样使用字段字典创建 dtype 对象:

>>> x = np.dtype({"field1": (float, 1), "field2": (int, 3)}) 

尽管这是有效的 NumPy 代码,类型检查器会对其提出异议,因为不鼓励使用。请参见:数据类型对象

数字精度

numpy.number子类的精度被视为协变通用参数(参见NBitBase),简化了涉及基于精度的转换的注释过程。

>>> from typing import TypeVar
>>> import numpy as np
>>> import numpy.typing as npt

>>> T = TypeVar("T", bound=npt.NBitBase)
>>> def func(a: "np.floating[T]", b: "np.floating[T]") -> "np.floating[T]":
...     ... 

因此,float16float32float64等类型仍然是floating的子类型,但与运行时相反,它们不一定被视为子类。

Timedelta64

timedelta64 类不被视为signedinteger的子类,前者仅在静态类型检查中继承自generic

零维数组

在运行时,NumPy 会将任何传递的 0 维数组强制转换为相应的generic实例。在引入形状类型编制(参见PEP 646)之前,不幸的是目前无法区分 0 维和>0 维数组。因此,所有可能进行 0 维数组 -> 标量转换的操作当前都被注释地专门返回一个ndarray,虽然这不严格正确。

如果预先知道一个操作将执行 0 维数组 -> 标量转换,那么可以考虑使用typing.cast# type: ignore注释手动处理情况。

记录数组 dtypes

numpy.recarray的 dtype,以及一般的numpy.rec函数,可以通过两种方式指定:

  • 直接通过dtype参数。

  • 通过numpy.format_parser提供的最多五个帮助参数进行操作:formatsnamestitlesalignedbyteorder

目前,这两种方法被彼此排斥化为互斥,如果指定了dtype,则不能指定formats。尽管这种互斥在运行时并没有(严格)执行,但结合两种 dtype 说明符可能会导致意外或严重错误行为。

ArrayLike

ArrayLike类型尝试避免创建对象数组。例如,

>>> np.array(x**2 for x in range(10))
array(<generator object <genexpr> at ...>, dtype=object) 

是有效的 NumPy 代码,它将创建一个 0 维对象数组。然而,当使用 NumPy 类型时,类型检查器会对上述示例报错。如果您真的打算执行上述操作,那么您可以使用# type: ignore注释:

>>> np.array(x**2 for x in range(10))  # type: ignore 

或者将类似数组的对象明确类型为Any:

>>> from typing import Any
>>> array_like: Any = (x**2 for x in range(10))
>>> np.array(array_like)
array(<generator object <genexpr> at ...>, dtype=object) 

ndarray

可以在运行时更改数组的 dtype。例如,以下代码是有效的:

>>> x = np.array([1, 2])
>>> x.dtype = np.bool_ 

类型不允许进行此类变异。希望编写静态类型代码的用户应该使用 numpy.ndarray.view 方法以不同的 dtype 创建数组的视图。

DTypeLike

DTypeLike类型尝试避免使用以下格式的字段字典创建 dtype 对象:

>>> x = np.dtype({"field1": (float, 1), "field2": (int, 3)}) 

尽管这是有效的 NumPy 代码,但类型检查器会对其报错,因为它的使用是不鼓励的。请参阅:数据类型对象

数值精度

numpy.number子类的精度被视为协变通用参数(参见NBitBase

def func(a: "np.floating[T]", b: "np.floating[T]") -> "np.floating[T]":
... ...


因此,`float16`、`float32`和`float64`仍然是`floating`的子类型,但与运行时相反,它们不一定被视为子类。

### Timedelta64

在静态类型检查中,`timedelta64`类不被视为`signedinteger`的子类,前者仅继承自 `generic`。

### 0D 数组

运行时,numpy 会将任何传入的 0D 数组强制转换为相应的`generic`实例。在引入 shape typing(参见[**PEP 646**](https://peps.python.org/pep-0646/)) 之前,不幸的是无法对 0D 和>0D 数组进行必要的区分。因此,虽然不严格正确,但目前将所有可能执行 0D-array -> scalar 转换的操作都注释为仅返回*ndarray*。

如果预先知道一个操作 _will_ 执行 0D-array -> 标量转换,则可以考虑使用[`typing.cast`](https://docs.python.org/3/library/typing.html#typing.cast "(在 Python v3.11)")或者`# type: ignore`注释手动解决这种情况。

### 记录数组 dtypes

`numpy.recarray`的 dtype,以及通用的`numpy.rec`函数,可以通过两种方式指定:

+   通过`dtype`参数直接指定。

+   通过`numpy.format_parser`操作的最多五个辅助参数: `formats`、`names`、`titles`、`aligned`和`byteorder`。

目前这两种方法的类型被定义为互斥的,*即*如果指定了`dtype`,则不允许指定`formats`。虽然这种互斥性在运行时并没有(严格)强制执行,但结合两种 dtype 指定器可能会导致意外或甚至严重的错误行为。

## API

```py
numpy.typing.ArrayLike = typing.Union[...]

代表可以强制转换为ndarrayUnion

其中包括:

  • 标量。

  • (嵌套) 序列。

  • 实现array协议的对象。

1.20 版中的新功能。

参见

array_like:

任何可以解释为 ndarray 的标量或序列。

例子

>>> import numpy as np
>>> import numpy.typing as npt

>>> def as_array(a: npt.ArrayLike) -> np.ndarray:
...     return np.array(a) 
numpy.typing.DTypeLike = typing.Union[...]

代表可以被强制转换为dtype的对象的Union

其中包括:

  • type 对象。

  • 字符代码或type对象的名称。

  • 具有.dtype属性的对象。

1.20 版中的新功能。

参见

指定和构造数据类型

所有可强制转换为数据类型的对象的全面概述。

例子

>>> import numpy as np
>>> import numpy.typing as npt

>>> def as_dtype(d: npt.DTypeLike) -> np.dtype:
...     return np.dtype(d) 
numpy.typing.NDArray = numpy.ndarray[typing.Any, numpy.dtype[+_ScalarType_co]]

np.ndarray[Any, np.dtype[+ScalarType]]通用版本。

可以在运行时用于对具有给定 dtype 和未指定形状的数组进行类型标记。

1.21 版中的新功能。

例子

>>> import numpy as np
>>> import numpy.typing as npt

>>> print(npt.NDArray)
numpy.ndarray[typing.Any, numpy.dtype[+ScalarType]]

>>> print(npt.NDArray[np.float64])
numpy.ndarray[typing.Any, numpy.dtype[numpy.float64]]

>>> NDArrayInt = npt.NDArray[np.int_]
>>> a: NDArrayInt = np.arange(10)

>>> def func(a: npt.ArrayLike) -> npt.NDArray[Any]:
...     return np.array(a) 
class numpy.typing.NBitBase

用于静态类型检查期间的numpy.number精度类型。

仅供静态类型检查目的使用,NBitBase 表示一组子类的基类。每个后续子类在此用于表示更低级的精度,e.g. 64Bit > 32Bit > 16Bit

1.20 版中的新功能。

例子

下面是一个典型的使用示例:NBitBase 在这里用于注释一个接受任意精度的浮点数和整数作为参数,并返回具有最大精度的新浮点数的函数(例如 np.float16 + np.int64 -> np.float64)。

>>> from __future__ import annotations
>>> from typing import TypeVar, TYPE_CHECKING
>>> import numpy as np
>>> import numpy.typing as npt

>>> T1 = TypeVar("T1", bound=npt.NBitBase)
>>> T2 = TypeVar("T2", bound=npt.NBitBase)

>>> def add(a: np.floating[T1], b: np.integer[T2]) -> np.floating[T1 | T2]:
...     return a + b

>>> a = np.float16()
>>> b = np.int64()
>>> out = add(a, b)

>>> if TYPE_CHECKING:
...     reveal_locals()
...     # note: Revealed local types are:
...     # note:     a: numpy.floating[numpy.typing._16Bit*]
...     # note:     b: numpy.signedinteger[numpy.typing._64Bit*]
...     # note:     out: numpy.floating[numpy.typing._64Bit*] 

全局状态

原文:numpy.org/doc/1.26/reference/global_state.html

NumPy 具有一些导入时、编译时或运行时选项,可以更改全局行为。其中大多数与性能或调试目的有关,对绝大多数用户来说不会有太大兴趣。

与性能相关的选项

用于线性代数的线程数

NumPy 本身通常在函数调用期间有意限制为单个线程,但它确实支持同时运行多个 Python 线程。请注意,对于性能良好的线性代数,NumPy 使用 OpenBLAS 或 MKL 等 BLAS 后端,这可能使用多个线程,这些线程可以通过环境变量(如OMP_NUM_THREADS)进行控制,具体取决于使用了什么。控制线程数的一种方法是使用 threadpoolctl 包。

Linux 上的 Madvise Hugepage

在现代 Linux 内核上操作非常大的数组时,当使用透明大页时,您会体验到显着的加速。可以通过以下方式查看透明大页的当前系统策略:

cat /sys/kernel/mm/transparent_hugepage/enabled 

将其设置为madvise时,NumPy 通常会使用 hugepages 来提高性能。通过设置环境变量可以修改此行为:

NUMPY_MADVISE_HUGEPAGE=0 

或将其设置为1 以始终启用它。未设置时,默认值是在内核 4.6 及更高版本上使用 madvise。这些内核应该通过 hugepage 支持实现大幅加速。此标志在导入时进行检查。

SIMD 特性选择

设置NPY_DISABLE_CPU_FEATURES将在运行时排除 simd 特性。详见运行时分发。

与调试相关的选项

松散的步幅检查

编译时环境变量:

NPY_RELAXED_STRIDES_DEBUG=0 

可以设置以帮助调试通过 C 编写的代码,手动遍历数组。当数组是连续的并以连续的方式遍历时,不应查询其strides。此选项可帮助找到错误,其中strides被错误使用。有关详细信息,请参见内存布局文档。

在释放数据时,如果没有内存分配策略则发出警告

某些用户可能通过设置OWNDATA标志将数据指针的所有权传递给ndarray。如果他们这样做而没有(手动)设置内存分配策略,则默认值将调用free。如果NUMPY_WARN_IF_NO_MEM_POLICY设置为"1",则会发出RuntimeWarning。更好的替代方法是使用带有解除分配器的PyCapsule并设置ndarray.base

测试计划未来的行为

NumPy 有一些代码路径,计划在将来激活,但目前不是默认行为。您可以尝试测试其中一些可能会与新的“主要”发布(NumPy 2.0)一起提供的功能,方法是在导入 NumPy 之前设置环境:

NPY_NUMPY_2_BEHAVIOR=1

默认情况下,这也会激活NEP 50相关的设置NPY_PROMOTION_STATE(请参阅 NEP 以获取详细信息)。

在 1.25.2 版本中更改:此变量仅在首次导入时被检查。

与性能相关的选项

用于线性代数的线程数

NumPy 本身通常在函数调用期间有意限制为单个线程,但支持同时运行多个 Python 线程。请注意,为了进行高性能的线性代数运算,NumPy 使用类似 OpenBLAS 或 MKL 的 BLAS 后端,该后端可能使用多个线程,这些线程可能受环境变量(如OMP_NUM_THREADS)的控制。控制线程数的一种方法是使用包threadpoolctl

Linux 上的 Madvise Hugepage

在现代 Linux 内核上操作非常大的数组时,启用透明大页 可以获得显着的加速。当前透明大页的系统策略可以通过以下方式查看:

cat /sys/kernel/mm/transparent_hugepage/enabled 

当设置为madvise时,NumPy 通常会使用大页来提升性能。可以通过设置环境变量来修改此行为:

NUMPY_MADVISE_HUGEPAGE=0 

或将其设置为1以始终启用。如果未设置,默认情况下在内核 4.6 及更新版本上使用 madvise。据称这些内核在支持大页的情况下会获得大幅加速。此标志在导入时会被检查。

SIMD 特性选择

设置NPY_DISABLE_CPU_FEATURES将在运行时排除 simd 特性。请参阅运行时调度。

用于线性代数的线程数

NumPy 本身通常在函数调用期间有意限制为单个线程,但支持同时运行多个 Python 线程。请注意,为了进行高性能的线性代数运算,NumPy 使用类似 OpenBLAS 或 MKL 的 BLAS 后端,该后端可能使用多个线程,这些线程可能受环境变量(如OMP_NUM_THREADS)的控制。控制线程数的一种方法是使用包threadpoolctl

Linux 上的 Madvise Hugepage

在现代 Linux 内核上操作非常大的数组时,启用透明大页 可以获得显着的加速。当前透明大页的系统策略可以通过以下方式查看:

cat /sys/kernel/mm/transparent_hugepage/enabled 

当设置为madvise时,NumPy 通常会使用大页来提升性能。可以通过设置环境变量来修改此行为:

NUMPY_MADVISE_HUGEPAGE=0 

或将其设置为1以始终启用。如果未设置,默认情况下在内核 4.6 及更新版本上使用 madvise。据称这些内核在支持大页的情况下会获得大幅加速。此标志在导入时会被检查。

SIMD 特性选择

设置 NPY_DISABLE_CPU_FEATURES 将在运行时排除 simd 功能。请参阅 运行时调度。

与调试相关的选项

放松的strides检查

编译时环境变量:

NPY_RELAXED_STRIDES_DEBUG=0 

可以设置以帮助调试用 C 编写的代码,该代码手动遍历数组。当数组连续并以连续方式迭代时,不应查询其strides。此选项可帮助找出错误,其中strides被错误使用。有关详细信息,请参阅 内存布局 文档。

在释放数据时,如果没有内存分配策略,则发出警告

一些用户可能会通过设置ndarrayOWNDATA标志来将数据指针的所有权传递给ndarray。如果他们这样做而没有设置(手动设置)内存分配策略,则默认将调用free。如果将NUMPY_WARN_IF_NO_MEM_POLICY设置为"1",则会发出RuntimeWarning。更好的替代方法是使用具有解除分配器的PyCapsule并设置ndarray.base

放松的strides检查

编译时环境变量:

NPY_RELAXED_STRIDES_DEBUG=0 

可以设置以帮助调试用 C 编写的代码,该代码手动遍历数组。当数组连续并以连续方式迭代时,不应查询其strides。此选项可帮助找出错误,其中strides被错误使用。有关详细信息,请参阅 内存布局 文档。

在释放数据时,如果没有内存分配策略,则发出警告

一些用户可能会通过设置ndarrayOWNDATA标志来将数据指针的所有权传递给ndarray。如果他们这样做而没有设置(手动设置)内存分配策略,则默认将调用free。如果将NUMPY_WARN_IF_NO_MEM_POLICY设置为"1",则会发出RuntimeWarning。更好的替代方法是使用具有解除分配器的PyCapsule并设置ndarray.base

计划的未来行为测试

NumPy 有一些代码路径,计划在将来激活,但目前不是默认行为。您可以通过在导入 NumPy 之前设置环境来尝试测试其中一些可能随新的“主要”版本(NumPy 2.0)一起发布的功能:

NPY_NUMPY_2_BEHAVIOR=1

默认情况下,这也会激活与 NEP 50 相关的设置 NPY_PROMOTION_STATE(请参阅 NEP 了解详情)。

从版本 1.25.2 开始更改:此变量仅在首次导入时进行检查。

打包(numpy.distutils

原文:numpy.org/doc/1.26/reference/distutils.html

警告

numpy.distutils 已被弃用,并将在 Python >= 3.12 版本中移除。更多详情,请参阅 Status of numpy.distutils and migration advice。

警告

请注意,setuptools经常进行重大发布,可能包含破坏numpy.distutils的更改,而numpy.distutils将不再针对新的setuptools版本进行更新。因此,建议在您的构建配置中设置一个上限版本,以确保最后已知可与您的构建配合使用的setuptools版本。

NumPy 提供了增强的 distutils 功能,使构建和安装子包、自动生成代码以及使用 Fortran 编译库的扩展模块更容易。要使用 NumPy distutils 的功能,请使用numpy.distutils.core中的 setup 命令。同时,numpy.distutils.misc_util 还提供了一个有用的 Configuration 类,可以更轻松地构建传递给 setup 函数的关键字参数(通过传递从该类的 todict() 方法获得的字典)。更多信息请参阅 NumPy distutils - 用户指南。

选择和链接库的位置,例如 BLAS 和 LAPACK,以及包含路径等其他构建选项可以在 NumPy 根仓库中的 site.cfg 文件或者位于用户主目录中的 .numpy-site.cfg 文件中指定。参见在 NumPy 仓库或者 sdist 中附带的 site.cfg.example 示例文件获取文档。

numpy.distutils 中的模块

  • distutils.misc_util

    • all_strings

    • allpath

    • appendpath

    • as_list

    • blue_text

    • cyan_text

    • cyg2win32

    • default_config_dict

    • dict_append

    • dot_join

    • exec_mod_from_location

    • filter_sources

    • generate_config_py

    • get_build_architecture

    • get_cmd

    • get_data_files

    • get_dependencies

    • get_ext_source_files

    • get_frame

    • get_info

    • get_language

    • get_lib_source_files

    • get_mathlibs

    • get_num_build_jobs

    • get_numpy_include_dirs

    • get_pkg_info

    • get_script_files

    • gpaths

    • green_text

    • has_cxx_sources

    • has_f_sources

    • is_local_src_dir

    • is_sequence

    • is_string

    • mingw32

    • minrelpath

    • njoin

    • red_text

    • sanitize_cxx_flags

    • terminal_has_colors

    • yellow_text

ccompiler
ccompiler_opt 提供CCompilerOpt类,用于处理 CPU/硬件优化,从解析命令参数开始,到管理 CPU 基线和可调度特性之间的关系,还生成所需的 C 标头,并以合适的编译器标志编译源代码。
cpuinfo.cpu
core.Extension(name, sources[, ...])

参数:

|

exec_command exec_command
log.set_verbosity(v[, force])
system_info.get_info(name[, notfound_action]) notfound_action:
system_info.get_standard_file(fname) 从 1)系统范围的目录(这个模块的目录位置)2)用户 HOME 目录(os.environ['HOME'])3)本地目录返回一个名为“fname”的文件列表

配置类

class numpy.distutils.misc_util.Configuration(package_name=None, parent_name=None, top_path=None, package_path=None, **attrs)

为给定的包名称构造一个配置实例。如果parent_name不为 None,则构造包作为parent_name包的子包。如果top_pathpackage_path为 None,则它们被假定为与创建此实例的文件的路径相等。numpy 分配中的 setup.py 文件是如何使用Configuration实例的很好的例子。

todict()

返回一个与 distutils setup 函数的关键字参数兼容的字典。

例子

>>> setup(**config.todict()) 
get_distribution()

返回 self 的 distutils 分发对象。

get_subpackage(subpackage_name, subpackage_path=None, parent_name=None, caller_level=1)

返回子包配置列表。

参数:

subpackage_namestr 或 None

获取配置的子包的名称。在 subpackage_name 中的‘*’被视为通配符。

subpackage_pathstr

如果为 None,则假定路径为本地路径加上 subpackage_name。如果在 subpackage_path 中找不到 setup.py 文件,则使用默认配置。

parent_namestr

父名称。

add_subpackage(subpackage_name, subpackage_path=None, standalone=False)

向当前 Configuration 实例添加一个子包。

在 setup.py 脚本中,这对于向包添加子包非常有用。

参数:

subpackage_namestr

子包的名称

subpackage_pathstr

如果提供,则子包路径例如子包位于子包路径/子包名称。如果为 None,则假定子包位于本地路径/子包名称。

standalonebool

add_data_files(*files)

将数据文件添加到配置数据文件中。

参数:

files序列

参数可以是

  • 2-序列(<数据目录前缀>,<数据文件路径>)
  • 数据文件的路径,其中 python 数据目录前缀默认为包目录。

注意事项

文件序列的每个元素的形式非常灵活,允许从包中获取文件的多种组合以及它们应最终安装到系统的位置。最基本的用法是让文件参数序列的一个元素成为一个简单的文件名。这将导致将该文件从本地路径安装到 self.name 包的安装路径(包路径)。文件参数还可以是相对路径,此时整个相对路径将安装到包目录中。最后,文件可以是绝对路径名,此时文件将在绝对路径名处找到,但安装到包路径。

通过将 2 元组作为文件参数传递来增强此基本行为。元组的第一个元素应指定应将其余文件序列安装到的相对路径(在包安装目录下)(它与源分发中的文件名无关)。元组的第二个元素是应安装的文件序列。此序列中的文件可以是文件名、相对路径或绝对路径。对于绝对路径,文件将安装在顶级包安装目录中(不管第一个参数如何)。文件名和相对路径名将安装在给定为元组第一个元素的路径名下的包安装目录中。

安装路径规则:

  1. file.txt -> (., file.txt)-> parent/file.txt
  2. foo/file.txt -> (foo, foo/file.txt) -> parent/foo/file.txt
  3. /foo/bar/file.txt -> (., /foo/bar/file.txt) -> parent/file.txt
  4. *.txt -> parent/a.txt, parent/b.txt
  5. foo/*.txt`` -> parent/foo/a.txt, parent/foo/b.txt
  6. */*.txt -> (*, */*.txt) -> parent/c/a.txt, parent/d/b.txt
  7. (sun, file.txt) -> parent/sun/file.txt
  8. (sun, bar/file.txt) -> parent/sun/file.txt
  9. (sun, /foo/bar/file.txt) -> parent/sun/file.txt
  10. (sun, *.txt) -> parent/sun/a.txt, parent/sun/b.txt
  11. (sun, bar/*.txt) -> parent/sun/a.txt, parent/sun/b.txt
  12. (sun/*, */*.txt) -> parent/sun/c/a.txt, parent/d/b.txt

另一个特性是数据文件的路径实际上可以是一个不带参数且返回数据文件实际路径的函数。这在构建包时生成数据文件时非常有用。

示例

将文件添加到要随包一起包含的数据文件列表中。

>>> self.add_data_files('foo.dat',
...     ('fun', ['gun.dat', 'nun/pun.dat', '/tmp/sun.dat']),
...     'bar/cat.dat',
...     '/full/path/to/can.dat') 

将这些数据文件安装到:

<package install directory>/
 foo.dat
 fun/
   gun.dat
   nun/
     pun.dat
 sun.dat
 bar/
   car.dat
 can.dat 

其中是包(或子包)目录,例如‘/usr/lib/python2.4/site-packages/mypackage’(‘C: Python2.4 Lib site-packages mypackage’)或‘/usr/lib/python2.4/site- packages/mypackage/mysubpackage’(‘C: Python2.4 Lib site-packages mypackage mysubpackage’)。

add_data_dir(data_path)

递归地将 data_path 下的文件添加到 data_files 列表中。

递归地将 data_path 下的文件添加到要安装(和分发)的 data_files 列表中。data_path 可以是相对路径名、绝对路径名,或者是一个 2 元组,第一个参数指示数据目录应安装到安装目录的何处。

参数:

data_pathseq 或 str

参数可以是

  • 2 序列(<datadir 后缀>,<数据目录路径>)
  • 数据目录的路径,其中 python datadir 后缀默认为包目录。

安装路径规则:

foo/bar -> (foo/bar, foo/bar) -> parent/foo/bar
(gun, foo/bar) -> parent/gun
foo/* -> (foo/a, foo/a), (foo/b, foo/b) -> parent/foo/a, parent/foo/b
(gun, foo/*) -> (gun, foo/a), (gun, foo/b) -> gun
(gun/*, foo/*) -> parent/gun/a, parent/gun/b
/foo/bar -> (bar, /foo/bar) -> parent/bar
(gun, /foo/bar) -> parent/gun
(fun/*/gun/*, sun/foo/bar) -> parent/fun/foo/gun/bar 

示例

例如,假设源目录包含 fun/foo.dat 和 fun/bar/car.dat:

>>> self.add_data_dir('fun')                       
>>> self.add_data_dir(('sun', 'fun'))              
>>> self.add_data_dir(('gun', '/full/path/to/fun')) 

将数据文件安装到以下位置:

<package install directory>/
  fun/
    foo.dat
    bar/
      car.dat
  sun/
    foo.dat
    bar/
      car.dat
  gun/
    foo.dat
    car.dat 
add_include_dirs(*paths)

将路径添加到配置的包含目录中。

将给定的路径序列添加到 include_dirs 列表的开头。这个列表将���当前包的所有扩展模块可见。

add_headers(*files)

将可安装的头文件添加到配置中。

将给定的文件序列添加到头文件列表的开头。默认情况下,头文件将安装在/<self.name.replace(‘.’,’/’)>/目录下。如果 files 的项是元组,则其第一个参数指定相对于路径的实际安装位置。

参数:

filesstr 或 seq

参数可以是:

  • 2 序列(<includedir 后缀>,<头文件路径>)
  • 头文件路径,其中 python 包含目录后缀将默认为包名称。
add_extension(name, sources, **kw)

将扩展添加到配置中。

创建并将一个 Extension 实例添加到 ext_modules 列表中。此方法还接受以下可选关键字参数,这些参数传递给 Extension 构造函数。

参数:

namestr

扩展名

sourcesseq

源文件列表。源文件列表可能包含函数(称为源文件生成器),它们必须将扩展实例和构建目录作为输入,并返回一个源文件或源文件列表或 None。如果返回 None,则不生成任何源文件。如果处理完所有源文件生成器后 Extension 实例没有源文件,则不会构建扩展模块。

include_dirs

define_macros

undef_macros

library_dirs

libraries

runtime_library_dirs

extra_objects

extra_compile_args

extra_link_args

extra_f77_compile_args

extra_f90_compile_args

export_symbols

swig_opts

depends

依赖列表包含扩展模块源文件所依赖的文件或目录的路径。如果依赖列表中的任何路径比扩展模块更新,那么将重新构建该模块。

language

f2py_options

module_dirs

extra_infodict 或 list

要附加到关键字的关键字的字典或关键字的列表。

注释

对可能包含路径的所有列表应用 self.paths(…) 方法。

add_library(name, sources, **build_info)

将库添加到配置中。

参数:

namestr

扩展的名称。

sources序列

源列表。源列表可能包含函数(称为源生成器),这些函数必须接受扩展实例和构建目录作为输入,并返回一个源文件或源文件列表或 None。如果返回 None,则不生成任何源。如果 Extension 实例在处理所有源生成器后没有源,则不会构建扩展模块。

build_info字典,可选

允许以下键:

  • 依赖项
  • include_dirs
  • extra_compiler_args
  • extra_f77_compile_args
  • extra_f90_compile_args
  • f2py_options
  • 语言
add_scripts(*files)

将脚本添加到配置中。

将文件序列添加到脚本列表的开头。脚本将安装在 /bin/ 目录下。

add_installed_library(name, sources, install_dir, build_info=None)

类似于 add_library,但安装指定的库。

大多数与 distutils 一起使用的 C 库仅用于构建 Python 扩展,但通过此方法构建的库将被安装,以便它们可以被第三方包重用。

参数:

namestr

安装的库的名称。

sources序列

库的源文件列表。有关详细信息,请参见 add_library

install_dirstr

库的安装路径,相对于当前子包。

build_info字典,可选

允许以下键:

  • 依赖项
  • include_dirs
  • extra_compiler_args
  • extra_f77_compile_args
  • extra_f90_compile_args
  • f2py_options
  • 语言

返回:

None

参见

add_libraryadd_npy_pkg_configget_info

注释

链接到指定的 C 库所需选项的最佳方法是使用“libname.ini”文件,并使用 get_info 检索所需的选项(有关更多信息,请参见 add_npy_pkg_config)。

add_npy_pkg_config(template, install_dir, subst_dict=None)

从模板生成并安装一个 npy-pkg 配置文件。

template 生成的配置文件将使用 subst_dict 进行变量替换,并安装在给定的安装目录中。

参数:

templatestr

模板的路径,相对于当前包路径。

install_dirstr

安装 npy-pkg 配置文件的位置,相对于当前软件包路径而言。

subst_dictdict,可选

如果提供了任何形式为 @key@ 的字符串,将在模板文件安装时将其替换为 subst_dict[key]。安装前缀始终可以通过变量 @prefix@ 获得,因为从 setup.py 可靠地获取安装前缀并不容易。

另请参见

add_installed_libraryget_info

这适用于标准安装和就地编译,即 @prefix@ 指的是就地编译的源目录。

示例

config.add_npy_pkg_config('foo.ini.in', 'lib', {'foo': bar}) 

假设 foo.ini.in 文件具有以下内容:

[meta]
Name=@foo@
Version=1.0
Description=dummy description

[default]
Cflags=-I@prefix@/include
Libs= 

生成的文件将具有以下内容:

[meta]
Name=bar
Version=1.0
Description=dummy description

[default]
Cflags=-Iprefix_dir/include
Libs= 

并将安装为 lib 子路径下的 foo.ini 文件。

当使用 numpy distutils 进行交叉编译时,可能需要使用修改后的 npy-pkg-config 文件。使用默认生成的文件将链接到主机库(即 libnpymath.a)。而在交叉编译时,必须链接到目标库,同时使用主机 Python 安装。

您可以拷贝 numpy/core/lib/npy-pkg-config 目录,向 .ini 文件中添加 pkgdir 值,并将 NPY_PKG_CONFIG_PATH 环境变量设置为指向修改后的 npy-pkg-config 文件所在的目录。

修改的 npymath.ini 示例用于交叉编译:

[meta]
Name=npymath
Description=Portable, core math library implementing C99 standard
Version=0.1

[variables]
pkgname=numpy.core
pkgdir=/build/arm-linux-gnueabi/sysroot/usr/lib/python3.7/site-packages/numpy/core
prefix=${pkgdir}
libdir=${prefix}/lib
includedir=${prefix}/include

[default]
Libs=-L${libdir} -lnpymath
Cflags=-I${includedir}
Requires=mlib

[msvc]
Libs=/LIBPATH:${libdir} npymath.lib
Cflags=/INCLUDE:${includedir}
Requires=mlib 
paths(*paths, **kws)

对路径应用 glob 并根据需要添加 local_path。

对序列中的每个路径应用 glob.glob(…)(如果需要),并根据需要添加 local_path。因为此方法在所有源列表上调用,所以可以在扩展模块、库、脚本的源列表中指定通配符和相对于源目录的路径名。

get_config_cmd()

返回 numpy.distutils 配置命令的实例。

get_build_temp_dir()

返回应放置临时文件的临时目录的路径。

have_f77c()

检查 Fortran 77 编译器的可用性。

在源代码生成函数中使用它,以确保设置的发行实例已被初始化。

如果存在 Fortran 77 编译器(因为简单的 Fortran 77 代码能够成功编译),则为真。

have_f90c()

检查 Fortran 90 编译器的可用性。

在源代码生成函数中使用它,以确保设置的发行实例已被初始化。

如果存在 Fortran 90 编译器(因为简单的 Fortran 90 代码能够成功编译),则为真。

get_version(version_file=None, version_variable=None)

尝试获取软件包的版本字符串。

返回当前软件包的版本字符串,如果无法检测到版本信息,则返回 None。

该方法扫描名为 version.py、_version.py、version.py 和 svn_version.py 的文件,以查找字符串变量 version、version_version,直到找到版本号。

make_svn_version_py(delete=True)

向 data_files 列表附加一个数据函数,用于在当前包目录中生成 svn_version.py 文件。

从 SVN 版本号生成包 svn_version.py 文件,它在 python 退出后将被删除,但在执行 sdist 等命令时可用。

注意

如果 svn_version.py 在之前存在,则不执行任何操作。

这适用于在 SVN 存储库中的源目录中的工作。

make_config_py(name='__config__')

生成包含在构建软件包期间使用的 system_info 信息的包 config.py 文件。

此文件将被安装到包安装目录中。

get_info(*names)

获取资源信息。

以单个字典的形式返回参数列表中所有名称的信息(来自 system_info.get_info)。

构建可安装的 C 库

传统的 C 库(通过add_library安装)不会被安装,仅在构建过程中使用(它们是静态链接的)。可安装的 C 库是一个纯 C 库,不依赖于 python C 运行时,并且被安装以便它可以被第三方软件包使用。要构建和安装 C 库,只需使用方法add_installed_library,而不是add_library,它除了额外的install_dir参数外,其他参数和add_library相同:

.. hidden in a comment so as to be included in refguide but not rendered documentation
  >>> import numpy.distutils.misc_util
  >>> config = np.distutils.misc_util.Configuration(None, '', '.')
  >>> with open('foo.c', 'w') as f: pass

>>> config.add_installed_library('foo', sources=['foo.c'], install_dir='lib') 

npy-pkg-config 文件

为了使必要的构建选项对第三方可用,您可以使用numpy.distutils中实现的npy-pkg-config机制。该机制基于包含所有选项的.ini 文件。.ini 文件与 pkg-config UNIX 实用程序使用的.pc 文件非常相似:

[meta]
Name: foo
Version: 1.0
Description: foo library

[variables]
prefix = /home/user/local
libdir = ${prefix}/lib
includedir = ${prefix}/include

[default]
cflags = -I${includedir}
libs = -L${libdir} -lfoo 

通常在构建时需要生成该文件,因为它仅需要在构建时才能获得一些已知信息(例如前缀)。如果使用Configuration方法add_npy_pkg_config,则大部分情况下会自动生成。假设我们有一个模板文件 foo.ini.in 如下所示:

[meta]
Name: foo
Version: @version@
Description: foo library

[variables]
prefix = @prefix@
libdir = ${prefix}/lib
includedir = ${prefix}/include

[default]
cflags = -I${includedir}
libs = -L${libdir} -lfoo 

以及 setup.py 中的以下代码:

>>> config.add_installed_library('foo', sources=['foo.c'], install_dir='lib')
>>> subst = {'version': '1.0'}
>>> config.add_npy_pkg_config('foo.ini.in', 'lib', subst_dict=subst) 

这将把文件 foo.ini 安装到目录 package_dir/lib 中,并且 foo.ini 文件将从 foo.ini.in 生成,其中每个@version@都将被替换为subst_dict['version']。字典还自动添加了一个额外的前缀替换规则,其中包含安装前缀(因为这不容易从 setup.py 中获取)。npy-pkg-config 文件也可以安装在与 numpy 使用的相同位置,使用从get_npy_pkg_dir函数返回的路径。

重用另一个软件包中的 C 库

信息可以很容易地从get_info函数中获取,该函数位于numpy.distutils.misc_util中:

>>> info = np.distutils.misc_util.get_info('npymath')
>>> config.add_extension('foo', sources=['foo.c'], extra_info=info)
<numpy.distutils.extension.Extension('foo') at 0x...> 

可以提供一个附加的 .ini 文件路径列表给 get_info

.src 文件的转换

NumPy distutils 支持自动转换命名为 .src 的源文件。此功能可用于维护非常相似的代码块,只需在块之间进行简单的更改。在设置的构建阶段中,如果遇到名为 .src 的模板文件,则会从模板构造一个名为 的新文件,并将其放置在生成目录中以供使用。支持两种模板转换形式。第一种形式用于命名为 .ext.src 的文件,其中 ext 是已识别的 Fortran 扩展名(f、f90、f95、f77、for、ftn、pyf)。第二种形式用于所有其他情况。请参阅 使用模板转换 .src 文件。

Modules in numpy.distutils

  • distutils.misc_util

    • all_strings

    • allpath

    • appendpath

    • as_list

    • blue_text

    • cyan_text

    • cyg2win32

    • default_config_dict

    • dict_append

    • dot_join

    • exec_mod_from_location

    • filter_sources

    • generate_config_py

    • get_build_architecture

    • get_cmd

    • get_data_files

    • get_dependencies

    • get_ext_source_files

    • get_frame

    • get_info

    • get_language

    • get_lib_source_files

    • get_mathlibs

    • get_num_build_jobs

    • get_numpy_include_dirs

    • get_pkg_info

    • get_script_files

    • gpaths

    • green_text

    • has_cxx_sources

    • has_f_sources

    • is_local_src_dir

    • is_sequence

    • is_string

    • mingw32

    • minrelpath

    • njoin

    • red_text

    • sanitize_cxx_flags

    • terminal_has_colors

    • yellow_text

ccompiler
ccompiler_opt 提供CCompilerOpt类,用于处理 CPU/硬件优化,从解析命令参数开始,管理 CPU 基线和可调度功能之间的关系,还生成所需的 C 头文件,最后以正确的编译器标志编译源代码。
cpuinfo.cpu
core.Extension(name, sources[, ...])

Parameters:

|

exec_command exec_command
log.set_verbosity(v[, force])
system_info.get_info(name[, notfound_action]) notfound_action:
system_info.get_standard_file(fname) 从以下位置之一返回名为 'fname' 的文件列表:1) 系统范围的目录(该模块的目录位置) 2) 用户主目录(os.environ['HOME']) 3) 本地目录

配置类

class numpy.distutils.misc_util.Configuration(package_name=None, parent_name=None, top_path=None, package_path=None, **attrs)

为给定的包名称构造一个配置实例。如果 parent_name 不为 None,则将包构造为 parent_name 包的子包。如果 top_path 和 package_path 为 None,则它们被假定为与创建此实例的文件的路径相等。numpy 分发中的 setup.py 文件是如何使用Configuration实例的好例子。

todict()

返回一个与 distutils 安装函数的关键字参数兼容的字典。

示例

>>> setup(**config.todict()) 
get_distribution()

返回 self 的 distutils 分发对象。

get_subpackage(subpackage_name, subpackage_path=None, parent_name=None, caller_level=1)

返回子包配置的列表。

参数:

subpackage_namestr 或 None

获取配置的子包名称。子包名称中的‘*’将被视为通配符处理。

subpackage_pathstr

如果为 None,则路径假定为本地路径加上 subpackage_name。如果在 subpackage_path 中找不到 setup.py 文件,则使用默认配置。

parent_namestr

父级名称。

add_subpackage(subpackage_name, subpackage_path=None, standalone=False)

将子包添加到当前 Configuration 实例中。

这在 setup.py 脚本中对包添加子包时非常有用。

参数:

subpackage_namestr

子包的名称。

subpackage_pathstr

如果提供了该参数,则子包的路径为 subpackage_path / subpackage_name。如果为 None,则假定子包位于本地路径 / subpackage_name。

standalonebool

add_data_files(*files)

将数据文件添加到配置数据文件中。

参数:

filessequence

参数可以是以下内容之一

  • 2-sequence(<datadir 前缀>,<数据文件的路径>)
  • 数据文件的路径,默认为包目录。

注意事项

文件序列的每个元素的形式非常灵活,允许从包中获取文件的许多组合,以及它们应该最终安装在系统上的位置。最基本的用法是将 files 参数序列的一个元素设置为简单的文件名。这将导致将本地路径的该文件安装到 self.name 包的安装路径(包路径)中。文件参数还可以是相对路径,这样将整个相对路径安装到包目录中。最后,文件可以是绝对路径名,在这种情况下,文件将在绝对路径名处找到,但安装到包路径中。

该基本行为可以通过将 2 元组作为文件参数传递进行增强。元组的第一个元素应指定应安装剩余一系列文件的相对路径(在包安装目录下)(与源分发中的文件名无关)。元组的第二个元素是应安装的文件序列。该序列中的文件可以是文件名,相对路径或绝对路径。对于绝对路径,该文件将安装在顶层包安装目录中(而不管第一个参数)。文件名和相对路径名将安装在作为元组第一个元素给出的路径名下的包安装目录中。

安装路径规则:

  1. file.txt -> (., file.txt)-> parent/file.txt
  2. foo/file.txt -> (foo, foo/file.txt) -> parent/foo/file.txt
  3. /foo/bar/file.txt -> (., /foo/bar/file.txt) -> parent/file.txt
  4. *.txt -> parent/a.txt,parent/b.txt
  5. foo/*.txt`` -> parent/foo/a.txt, parent/foo/b.txt
  6. */*.txt -> (*, */*.txt) -> parent/c/a.txt, parent/d/b.txt
  7. (sun, file.txt) -> parent/sun/file.txt
  8. (sun, bar/file.txt) -> parent/sun/file.txt
  9. (sun, /foo/bar/file.txt) -> parent/sun/file.txt
  10. (sun, *.txt) -> parent/sun/a.txt, parent/sun/b.txt
  11. (sun, bar/*.txt) -> parent/sun/a.txt, parent/sun/b.txt
  12. (sun/*, */*.txt) -> parent/sun/c/a.txt, parent/d/b.txt

一个附加特性是数据文件的路径实际上可以是一个不带参数并返回数据文件实际路径的函数。当数据文件在构建软件包时生成时,这将非常有用。

示例

将文件添加到要与该软件包一起包含的 data_files 列表中。

>>> self.add_data_files('foo.dat',
...     ('fun', ['gun.dat', 'nun/pun.dat', '/tmp/sun.dat']),
...     'bar/cat.dat',
...     '/full/path/to/can.dat') 

将这些数据文件安装到:

<package install directory>/
 foo.dat
 fun/
   gun.dat
   nun/
     pun.dat
 sun.dat
 bar/
   car.dat
 can.dat 

其中<包安装目录>是包(或子包)目录,例如'/usr/lib/python2.4/site-packages/mypackage'('C:Python2.4 Lib site-packages mypackage')或'/usr/lib/python2.4/site-packages/mypackage/mysubpackage'('C:Python2.4 Lib site-packages mypackage mysubpackage')。

add_data_dir(data_path)

递归地将 data_path 下的文件添加到 data_files 列表中。

递归地将 data_path 下的文件添加到要安装(和分发)的 data_files 列表中。data_path 可以是相对路径名,也可以是绝对路径名,还可以是一个 2 元组,其中第一个参数显示数据文件夹应安装到安装目录中的位置。

参数:

data_pathseq 或 str

参数可以是

  • 2 元组(<datadir 后缀>,<数据目录路径>)
  • 数据目录路径,其中 python datadir 后缀默认为包目录。

注意

安装路径规则:

foo/bar -> (foo/bar, foo/bar) -> parent/foo/bar
(gun, foo/bar) -> parent/gun
foo/* -> (foo/a, foo/a), (foo/b, foo/b) -> parent/foo/a, parent/foo/b
(gun, foo/*) -> (gun, foo/a), (gun, foo/b) -> gun
(gun/*, foo/*) -> parent/gun/a, parent/gun/b
/foo/bar -> (bar, /foo/bar) -> parent/bar
(gun, /foo/bar) -> parent/gun
(fun/*/gun/*, sun/foo/bar) -> parent/fun/foo/gun/bar 

示例

例如,假设源目录包含 fun/foo.dat 和 fun/bar/car.dat:

>>> self.add_data_dir('fun')                       
>>> self.add_data_dir(('sun', 'fun'))              
>>> self.add_data_dir(('gun', '/full/path/to/fun')) 

将数据文件安装到以下位置:

<package install directory>/
  fun/
    foo.dat
    bar/
      car.dat
  sun/
    foo.dat
    bar/
      car.dat
  gun/
    foo.dat
    car.dat 
add_include_dirs(*paths)

添加到配置包含目录的路径。

将给定的路径序列添加到 include_dirs 列表的开头。这个列表将对当前包的所有扩展模块可见。

add_headers(*files)

将可安装的头文件添加到配置中。

将给定的文件序列添加到头文件列表的开头。默认情况下,头文件将安装在/<self.name.replace(‘.’,‘/’)>/目录下。如果 files 的项目是元组,则其第一个参数指定相对于路径的实际安装位置。

参数:

files字符串或序列

参数可以是:

  • 2 元组(<includedir 后缀>,<头文件路径>)
  • 头文件的路径,其中 python include 目录后缀默认为包名称。
add_extension(name, sources, **kw)

添加扩展到配置。

创建并将一个 Extension 实例添加到 ext_modules 列表。此方法还接受以下可选关键字参数,这些参数传递给 Extension 构造函数。

参数:

name字符串

扩展的名称

sources序列

源文件列表。源文件列表可能包含函数(称为源代码生成器),其必须以扩展实例和构建目录为输入,并返回源文件或源文件列表或 None。如果返回 None,则不会生成任何源文件。如果扩展实例在处理所有源代码生成器后没有源文件,则不会构建任何扩展模块。

include_dirs

define_macros

undef_macros

library_dirs

libraries

runtime_library_dirs

extra_objects

extra_compile_args

extra_link_args

extra_f77_compile_args

extra_f90_compile_args

export_symbols

swig_opts

depends

depends 列表包含扩展模块的来源依赖的文件或目录路径。如果 depends 列表中的任何路径比扩展模块更新,那么模块将被重建。

language

f2py_options

module_dirs

extra_info字典或列表

字典或关键字列表以附加到关键字。

注意

对所有可能包含路径的列表应用 self.paths(...)方法。

add_library(name, sources, **build_info)

将库添加到配置。

参数:

name字符串

扩展的名称。

sources序列

源文件列表。源文件列表可能包含函数(称为源代码生成器),其必须以扩展实例和构建目录为输入,并返回源文件或源文件列表或 None。如果返回 None,则不会生成任何源文件。如果扩展实例在处理所有源代码生成器后没有源文件,则不会构建任何扩展模块。

build_info字典,可选

允许以下键:

  • depends
  • include_dirs
  • extra_compiler_args
  • extra_f77_compile_args
  • extra_f90_compile_args
  • f2py_options
  • 语言
add_scripts(*files)

添加脚本到配置。

将文件序列添加到脚本列表的开头。脚本将安装在/bin/目录下。

add_installed_library(name, sources, install_dir, build_info=None)

类似于 add_library,但指定的库已安装。

大多数与distutils一起使用的 C 库仅用于构建 Python 扩展,但通过此方法构建的库将被安装,以便它们可以被第三方包重复使用。

参数:

namestr

安装库的名称。

sourcessequence

库的源文件列表。有关详情,请参见add_library

install_dirstr

库的安装路径,相对于当前子包。

build_infodict,可选

允许以下键:

  • 依赖
  • include_dirs
  • extra_compiler_args
  • extra_f77_compile_args
  • extra_f90_compile_args
  • f2py_options
  • 语言

返回:

另请参阅

add_libraryadd_npy_pkg_configget_info

注释

链接到指定的 C 库所需选项的最佳方法是使用“libname.ini”文件,并使用get_info检索所需选项(有关更多信息,请参见add_npy_pkg_config)。

add_npy_pkg_config(template, install_dir, subst_dict=None)

从模板生成并安装一个 npy-pkg 配置文件。

template生成的配置文件使用subst_dict进行变量替换,并安装在给定的安装目录中。

参数:

templatestr

模板的路径,相对于当前包路径。

install_dirstr

安装 npy-pkg 配置文件的位置,相对于当前包路径。

subst_dictdict,可选

如果给定,任何形式为@key@的字符串在安装时都将在模板文件中被subst_dict[key]替换。由于从 setup.py 中可靠地获取安装前缀并不容易,所以安装前缀始终可通过变量@prefix@获得。

另请参阅

add_installed_libraryget_info

注释

这适用于标准安装和原地构建,即对于原地构建,@prefix@指的是源目录。

示例

config.add_npy_pkg_config('foo.ini.in', 'lib', {'foo': bar}) 

假设 foo.ini.in 文件具有以下内容:

[meta]
Name=@foo@
Version=1.0
Description=dummy description

[default]
Cflags=-I@prefix@/include
Libs= 

生成的文件将具有以下内容:

[meta]
Name=bar
Version=1.0
Description=dummy description

[default]
Cflags=-Iprefix_dir/include
Libs= 

并将安装为‘lib’子路径中的 foo.ini。

在使用 numpy distutils 进行交叉编译时,可能需要使用修改过的 npy-pkg-config 文件。使用默认/生成的文件将链接到宿主库(即 libnpymath.a)。在交叉编译时,你当然需要链接到目标库,同时使用宿主 Python 安装。

您可以将 numpy/core/lib/npy-pkg-config 目录复制出来,向 .ini 文件添加 pkgdir 值,并将 NPY_PKG_CONFIG_PATH 环境变量设置为指向修改后的 npy-pkg-config 文件的目录。

修改了用于交叉编译的 npymath.ini 示例:

[meta]
Name=npymath
Description=Portable, core math library implementing C99 standard
Version=0.1

[variables]
pkgname=numpy.core
pkgdir=/build/arm-linux-gnueabi/sysroot/usr/lib/python3.7/site-packages/numpy/core
prefix=${pkgdir}
libdir=${prefix}/lib
includedir=${prefix}/include

[default]
Libs=-L${libdir} -lnpymath
Cflags=-I${includedir}
Requires=mlib

[msvc]
Libs=/LIBPATH:${libdir} npymath.lib
Cflags=/INCLUDE:${includedir}
Requires=mlib 
paths(*paths, **kws)

对路径应用 glob 并在需要时在路径前加上 local_path。

对序列中的每个路径(如果需要)应用 glob.glob(…)并在需要时在路径前加上 local_path。因为这在所有源列表上都会被调用,这允许在扩展模块、库和脚本的源列表中指定通配符字符,同时也允许路径名相对于源目录。

get_config_cmd()

返回 numpy.distutils 配置命令实例。

get_build_temp_dir()

返回一个临时目录的路径,用于存放临时文件。

have_f77c()

检查是否可用 Fortran 77 编译器。

在源生成函数内部使用,以确保设置分发实例已被初始化。

注意

如果可用(因为能够成功编译简单的 Fortran 77 代码),则返回 True。

have_f90c()

检查是否可用 Fortran 90 编译器。

在源生成函数内部使用,以确保设置分发实例已被初始化。

注意

如果可用(因为能够成功编译简单的 Fortran 90 代码),则返回 True。

get_version(version_file=None, version_variable=None)

尝试获取包的版本字符串。

返回当前包的版本字符串,如果无法检测到版本信息,则返回 None。

注意

此方法扫描名为 version.py、_version.py、version.py 和 svn_version.py 的文件,查找字符串变量 version、version_version,直到找到版本号为止。

make_svn_version_py(delete=True)

向 data_files 列表添加一个生成 svn_version.py 文件的数据函数,将其生成到当前包目录。

从 SVN 修订号生成包 svn_version.py 文件,它将在 Python 退出时被移除,但在执行 sdist 等命令时仍然可用。

注意

如果 svn_version.py 存在,则不进行任何操作。

这是为了处理处于 SVN 代码库中的源目录而设计的。

make_config_py(name='__config__')

生成包含在构建包期间使用的 system_info 信息的包 config.py 文件。

此文件将安装到包安装目录中。

get_info(*names)

获取资源信息。

以单个字典的形式返回参数列表中所有名称的信息(来自 system_info.get_info)。

构建可安装的 C 库

传统的 C 库(通过 add_library 安装)不会被安装,而只是在构建期间使用(它们是静态链接的)。可安装的 C 库是一个纯 C 库,不依赖于 python C 运行时,并且被安装以便第三方包可以使用。要构建和安装 C 库,只需使用方法 add_installed_library 而不是 add_library,它接受相同的参数,除了额外的 install_dir 参数:

.. hidden in a comment so as to be included in refguide but not rendered documentation
  >>> import numpy.distutils.misc_util
  >>> config = np.distutils.misc_util.Configuration(None, '', '.')
  >>> with open('foo.c', 'w') as f: pass

>>> config.add_installed_library('foo', sources=['foo.c'], install_dir='lib') 

npy-pkg-config 文件

要使必要的构建选项对第三方可用,可以使用 npy-pkg-config 机制,该机制在 numpy.distutils 中实现。该机制基于一个 .ini 文件,其中包含所有选项。一个 .ini 文件与 pkg-config unix 实用程序使用的 .pc 文件非常相似:

[meta]
Name: foo
Version: 1.0
Description: foo library

[variables]
prefix = /home/user/local
libdir = ${prefix}/lib
includedir = ${prefix}/include

[default]
cflags = -I${includedir}
libs = -L${libdir} -lfoo 

通常,文件需要在构建期间生成,因为它只在构建时需要一些仅在构建时已知的信息(例如前缀)。如果使用了 Configuration 方法 add_npy_pkg_config,那么这主要是自动的。假设我们有一个模板文件 foo.ini.in,如下所示:

[meta]
Name: foo
Version: @version@
Description: foo library

[variables]
prefix = @prefix@
libdir = ${prefix}/lib
includedir = ${prefix}/include

[default]
cflags = -I${includedir}
libs = -L${libdir} -lfoo 

以及在 setup.py 中的以下代码:

>>> config.add_installed_library('foo', sources=['foo.c'], install_dir='lib')
>>> subst = {'version': '1.0'}
>>> config.add_npy_pkg_config('foo.ini.in', 'lib', subst_dict=subst) 

这将把文件 foo.ini 安装到目录 package_dir/lib 中,并且 foo.ini 文件将从 foo.ini.in 生成,其中每个 @version@ 将被 subst_dict['version'] 替换。字典还自动添加了一个额外的前缀替换规则,其中包含安装前缀(因为这在 setup.py 中不容易获取)。npy-pkg-config 文件也可以安装到与 numpy 使用的相同位置,使用从 get_npy_pkg_dir 函数返回的路径。

从另一个包中重用 C 库

信息可以轻松地从 numpy.distutils.misc_util 中的 get_info 函数中检索到:

>>> info = np.distutils.misc_util.get_info('npymath')
>>> config.add_extension('foo', sources=['foo.c'], extra_info=info)
<numpy.distutils.extension.Extension('foo') at 0x...> 

额外的 .ini 文件搜索路径列表可以提供给 get_info

npy-pkg-config 文件

要使必要的构建选项对第三方可用,可以使用 npy-pkg-config 机制,该机制在 numpy.distutils 中实现。该机制基于一个 .ini 文件,其中包含所有选项。一个 .ini 文件与 pkg-config unix 实用程序使用的 .pc 文件非常相似:

[meta]
Name: foo
Version: 1.0
Description: foo library

[variables]
prefix = /home/user/local
libdir = ${prefix}/lib
includedir = ${prefix}/include

[default]
cflags = -I${includedir}
libs = -L${libdir} -lfoo 

通常,文件需要在构建期间生成,因为它只在构建时需要一些仅在构建时已知的信息(例如前缀)。如果使用了 Configuration 方法 add_npy_pkg_config,那么这主要是自动的。假设我们有一个模板文件 foo.ini.in,如下所示:

[meta]
Name: foo
Version: @version@
Description: foo library

[variables]
prefix = @prefix@
libdir = ${prefix}/lib
includedir = ${prefix}/include

[default]
cflags = -I${includedir}
libs = -L${libdir} -lfoo 

以及在 setup.py 中的以下代码:

>>> config.add_installed_library('foo', sources=['foo.c'], install_dir='lib')
>>> subst = {'version': '1.0'}
>>> config.add_npy_pkg_config('foo.ini.in', 'lib', subst_dict=subst) 

这将把文件 foo.ini 安装到目录 package_dir/lib 中,并且 foo.ini 文件将从 foo.ini.in 生成,其中每个 @version@ 将被 subst_dict['version'] 替换。字典还会自动添加一个额外的前缀替换规则,其中包含安装前缀(因为这在 setup.py 中不容易获取)。npy-pkg-config 文件也可以安装到与 numpy 使用的相同位置,使用从 get_npy_pkg_dir 函数返回的路径。

重用另一个软件包中的 C 库

信息可以轻松从 numpy.distutils.misc_util 中的 get_info 函数中检索:

>>> info = np.distutils.misc_util.get_info('npymath')
>>> config.add_extension('foo', sources=['foo.c'], extra_info=info)
<numpy.distutils.extension.Extension('foo') at 0x...> 

可以向 get_info 函数提供一个额外的路径列表,用于查找 .ini 文件。

.src 文件的转换

NumPy distutils 支持自动转换命名为 .src 的源文件。这个功能可以用来维护非常相似的代码块,只需要在块之间进行简单的更改。在设置的构建阶段中,如果遇到名为 .src 的模板文件,则会从模板构建一个新文件命名为 并放置在构建目录中以供使用。支持两种形式的模板转换。第一种形式适用于以已识别的 Fortran 扩展名(f、f90、f95、f77、for、ftn、pyf)命名的文件。第二种形式适用于所有其他情况。请参阅使用模板转换 .src 文件。

numpy.distutils.misc_util

原文:numpy.org/doc/1.26/reference/distutils/misc_util.html

numpy.distutils.misc_util.all_strings(lst)

如果 lst 中的所有项都是字符串对象,则返回 True。

numpy.distutils.misc_util.allpath(name)

将一个 / 分隔的路径名转换为使用 OS 路径分隔符的路径。

numpy.distutils.misc_util.appendpath(prefix, path)
numpy.distutils.misc_util.as_list(seq)
numpy.distutils.misc_util.blue_text(s)
numpy.distutils.misc_util.cyan_text(s)
numpy.distutils.misc_util.cyg2win32(path: str) → str

将路径从 Cygwin 本地转换为 Windows 本地。

使用 cygpath 实用程序(Base 安装的一部分)进行实际转换。如果失败,则回退返回原始路径。

处理默认的 /cygdrive 挂载前缀以及 /proc/cygdrive 便携前缀,自定义的 cygdrive 前缀如 //mnt,以及绝对路径如 /usr/src//home/username

参数:

pathstr

要转换的路径

返回:

converted_pathstr

转换后的路径

笔记

cygpath 实用程序文档:cygwin.com/cygwin-ug-net/cygpath.html 它包装的 C 函数文档:cygwin.com/cygwin-api/func-cygwin-conv-path.html

numpy.distutils.misc_util.default_config_dict(name=None, parent_name=None, local_path=None)

返回一个配置字典,用于配置文件 setup_.py 中定义的 configuration() 函数的使用。

numpy.distutils.misc_util.dict_append(d, **kws)
numpy.distutils.misc_util.dot_join(*args)
numpy.distutils.misc_util.exec_mod_from_location(modname, modfile)

使用 importlib 机制从文件 modfile 导入模块 modname。根据 spec.loader,模块可能未在 sys.modules 中注册。

numpy.distutils.misc_util.filter_sources(sources)

返回包含 C、C++、Fortran 和 Fortran 90 模块源文件名称的四个列表。

numpy.distutils.misc_util.generate_config_py(target)

生成包含在构建软件包过程中使用的 system_info 信息的 config.py 文件。

用法:

config[‘py_modules’].append((packagename, ‘config’,generate_config_py))

numpy.distutils.misc_util.get_build_architecture()
numpy.distutils.misc_util.get_cmd(cmdname, _cache={})
numpy.distutils.misc_util.get_data_files(data)
numpy.distutils.misc_util.get_dependencies(sources)
numpy.distutils.misc_util.get_ext_source_files(ext)
numpy.distutils.misc_util.get_frame(level=0)

从调用堆栈中返回给定级别的帧对象。

numpy.distutils.misc_util.get_info(pkgname, dirs=None)

为给定 C 库返回一个 info 字典。

info 字典包含了使用 C 库所需的选项。

参数:

pkgnamestr

包的名称(应与 .ini 文件的名称匹配,不带扩展名,例如,文件 foo.ini 对应的名称为 foo)。

dirssequence, optional

如果给定,应为额外目录序列,用于查找 npy-pkg-config 文件。在 NumPy 目录之前搜索这些目录。

返回:

infodict

具有构建信息的字典。

引发:

PkgNotFound

如果找不到包。

另请参阅

Configuration.add_npy_pkg_configConfiguration.add_installed_library

get_pkg_info

示例

从 NumPy 获取 npymath 库所需的信息:

>>> npymath_info = np.distutils.misc_util.get_info('npymath')
>>> npymath_info                                    
{'define_macros': [], 'libraries': ['npymath'], 'library_dirs':
['.../numpy/core/lib'], 'include_dirs': ['.../numpy/core/include']} 

然后,此 info 字典可以作为 Configuration 实例的输入:

config.add_extension('foo', sources=['foo.c'], extra_info=npymath_info) 
numpy.distutils.misc_util.get_language(sources)

从源代码确定语言值(c,f77,f90)

numpy.distutils.misc_util.get_lib_source_files(lib)
numpy.distutils.misc_util.get_mathlibs(path=None)

返回 numpyconfig.h 中的 MATHLIB 行

numpy.distutils.misc_util.get_num_build_jobs()

获取由 setup.py 的--parallel 命令行参数设置的并行构建作业的数量。如果命令没有接收设置,则检查环境变量 NPY_NUM_BUILD_JOBS。如果未设置,则返回系统上的处理器数量,最多为 8 个(以防止系统超载,如果有大量 CPU)。

返回:

outint

可以运行的并行作业数量

numpy.distutils.misc_util.get_numpy_include_dirs()
numpy.distutils.misc_util.get_pkg_info(pkgname, dirs=None)

返回给定包的库信息。

参数:

pkgnamestr

包的名称(应与.ini 文件的名称匹配,不包括扩展名,例如对于文件 foo,包名应为 foo)。

dirs序列,可选

如果给出,应该是一个额外的目录序列,在这些目录中查找 npy-pkg-config 文件。在 NumPy 目录之前搜索这些目录。

返回:

pkginfo类实例

包含构建信息的LibraryInfo实例。

引发:

PkgNotFound

如果找不到包。

参见

Configuration.add_npy_pkg_configConfiguration.add_installed_library

get_info

numpy.distutils.misc_util.get_script_files(scripts)
numpy.distutils.misc_util.gpaths(paths, local_path='', include_non_existing=True)

对路径应用 glob,并在需要时添加 local_path。

numpy.distutils.misc_util.green_text(s)
numpy.distutils.misc_util.has_cxx_sources(sources)

如果 sources 包含 C ++文件,则返回 True

numpy.distutils.misc_util.has_f_sources(sources)

如果 sources 包含 Fortran 文件,则返回 True

numpy.distutils.misc_util.is_local_src_dir(directory)

如果目录是本地目录,则返回 True。

numpy.distutils.misc_util.is_sequence(seq)
numpy.distutils.misc_util.is_string(s)
numpy.distutils.misc_util.mingw32()

在使用 mingw32 环境时返回 True。

numpy.distutils.misc_util.minrelpath(path)

从路径中解析 *.

numpy.distutils.misc_util.njoin(*path)

连接两个或更多的路径名组件 + - 将一个以/分隔的路径名转换为使用 OS 的路径分隔符。- 从路径中解析 *和 *。

可以通过传递 n 个参数(例如 njoin('a','b')),或传递 n 个名称的序列(例如 njoin(['a','b'])),或这些参数的混合来处理。

numpy.distutils.misc_util.red_text(s)
numpy.distutils.misc_util.sanitize_cxx_flags(cxxflags)

一些标志对 C 有效但对 C ++无效。将它们剪切。

numpy.distutils.misc_util.terminal_has_colors()
numpy.distutils.misc_util.yellow_text(s)

numpy.distutils.ccompiler

原文:numpy.org/doc/1.26/reference/generated/numpy.distutils.ccompiler.html

函数

CCompiler_compile(self, sources[, ...]) 编译一个或多个源文件。
CCompiler_customize(self, dist[, need_cxx]) 对编译器实例进行任何特定于平台的定制。
CCompiler_customize_cmd(self, cmd[, ignore]) 使用 distutils 命令自定义编译器。
CCompiler_cxx_compiler(self) 返回 C++编译器。
CCompiler_find_executables(self) 此处无操作,但由 get_version 方法调用,可以被子类重写。
CCompiler_get_version(self[, force, ok_status]) 返回编译器版本,如果编译器不可用,则返回 None。
CCompiler_object_filenames(self, ...[, ...]) 返回给定源文件的对象文件的名称。
CCompiler_show_customization(self) 将编译器的定制打印到标准输出。
CCompiler_spawn(self, cmd[, display, env]) 在子进程中执行命令。
gen_lib_options(compiler, library_dirs, ...)
new_compiler([plat, compiler, verbose, ...])
replace_method(klass, method_name, func)
simple_version_match([pat, ignore, start]) 版本号简单匹配,用于 CCompiler 和 FCompiler。

numpy.distutils.ccompiler_opt

原文:numpy.org/doc/1.26/reference/generated/numpy.distutils.ccompiler_opt.html

提供 CCompilerOpt 类,用于处理 CPU/硬件优化,从解析命令参数开始,到管理 CPU 基线和可调度特性之间的关系,还生成所需的 C 头文件,最后使用适当的编译器标志编译源代码。

CCompilerOpt 不提供对 CPU 特性的运行时检测,而是仅关注编译器方面,但它创建了可以在最终运行时调度过程中后续使用的抽象 C 头文件。

函数

new_ccompiler_opt(compiler, dispatch_hpath, ...) 创建一个新的 'CCompilerOpt' 实例,并生成包含启用的 CPU 基线和可调度特性的平台特定指令集的 #定义和头文件的调度头文件。

CCompilerOpt(ccompiler[, cpu_baseline, ...]) 一个辅助类用于CCompiler,旨在提供额外的构建选项,以有效地控制与 CPU 特性直接相关的编译器优化。

numpy.distutils.cpuinfo.cpu

原文:numpy.org/doc/1.26/reference/generated/numpy.distutils.cpuinfo.cpu.html

distutils.cpuinfo.cpu = <numpy.distutils.cpuinfo.LinuxCPUInfo object>

numpy.distutils.core.Extension

原文:numpy.org/doc/1.26/reference/generated/numpy.distutils.core.Extension.html

class numpy.distutils.core.Extension(name, sources, include_dirs=None, define_macros=None, undef_macros=None, library_dirs=None, libraries=None, runtime_library_dirs=None, extra_objects=None, extra_compile_args=None, extra_link_args=None, export_symbols=None, swig_opts=None, depends=None, language=None, f2py_options=None, module_dirs=None, extra_c_compile_args=None, extra_cxx_compile_args=None, extra_f77_compile_args=None, extra_f90_compile_args=None)

参数:

namestr

扩展名。

sourcesstr 列表

源文件相对于包顶级目录的位置列表。

extra_compile_argsstr 列表

传递给编译器的额外命令行参数。

extra_f77_compile_argsstr 列表

传递给 fortran77 编译器的额外命令行参数。

extra_f90_compile_argsstr 列表

传递给 fortran90 编译器的额外命令行参数。

方法

has_cxx_sources
has_f2py_sources

numpy.distutils.exec_command

原文:numpy.org/doc/1.26/reference/generated/numpy.distutils.exec_command.html

exec_command

实现了几乎等同于 commands.getstatusoutput 函数的 exec_command 函数,但在 NT、DOS 系统上返回的状态实际上是正确的(虽然返回的状态值可能会有所不同)。此外,exec_command 采用关键字参数来(重新)定义环境变量。

提供函数:

exec_command — 在指定目录中执行命令

在修改后的环境中。

find_executable — 利用环境信息找到一个命令

变量 PATH。相当于 posix 的which命令。

作者:Pearu Peterson pearu@cens.ioc.ee 创建日期:2003 年 1 月 11 日

需要:Python 2.x

成功测试:

os.name sys.platform comments
posix linux2 Debian (sid) Linux, Python 2.1.3+, 2.2.3+, 2.3.3 PyCrust 0.9.3, Idle 1.0.2
posix linux2 Red Hat 9 Linux, Python 2.1.3, 2.2.2, 2.3.2
posix sunos5 SunOS 5.9, Python 2.2, 2.3.2
posix darwin Darwin 7.2.0, Python 2.3
nt win32 Windows Me Python 2.3(EE), Idle 1.0, PyCrust 0.7.2 Python 2.1.1 Idle 0.8
nt win32 Windows 98, Python 2.1.1. Idle 0.8
nt win32 Cygwin 98-4.10, Python 2.1.1(MSC) - echo 测试失败,即重新定义环境变量可能无效。已修复:不使用 cygwin echo!评论:cmd /c echo也不能工作,但重新定义环境变量可以工作。
posix cygwin Cygwin 98-4.10, Python 2.3.3(cygming special)
nt win32 Windows XP, Python 2.3.3

已知的错误:

  • 从 MSYS 提示符中执行时,向 stderr 发送消息的测试失败,因为在某个时候消息会丢失。

函数

exec_command(command[, execute_in, ...]) 返回执行命令的状态和输出。
filepath_from_subprocess_output(output) 将子进程使用编码的bytes转换为适合文件系统的str
find_executable(exe[, path, _cache]) 返回可执行文件的完整路径,如果不存在则返回 None。
forward_bytes_to_stdout(val) 将子进程调用的字节直接转发到控制台,而不尝试解码它们。
get_pythonexe()
temp_file_name()

numpy.distutils.log.set_verbosity

原文:numpy.org/doc/1.26/reference/generated/numpy.distutils.log.set_verbosity.html

distutils.log.set_verbosity(v, force=False)

numpy.distutils.system_info.get_info

原文:numpy.org/doc/1.26/reference/generated/numpy.distutils.system_info.get_info.html

distutils.system_info.get_info(name, notfound_action=0)

notfound_action:

0 - 什么也不做 1 - 显示警告消息 2 - 引发错误

numpy.distutils.system_info.get_standard_file

原文:numpy.org/doc/1.26/reference/generated/numpy.distutils.system_info.get_standard_file.html

distutils.system_info.get_standard_file(fname)

返回一个名为'fname'的文件列表,来自于:1)系统范围的目录(本模块的目录位置)2)用户的 HOME 目录(os.environ['HOME'])3)本地目录

NumPy distutils - 用户指南

原文:numpy.org/doc/1.26/reference/distutils_guide.html

警告

numpy.distutils 已弃用,并将在 Python >= 3.12 中移除。有关更多详情,请参见 numpy.distutils 的状态和迁移建议

SciPy 结构

目前 SciPy 项目包含两个包:

  • NumPy — 它提供如下包:

    • numpy.distutils - Python distutils 的扩展

    • numpy.f2py - 将 Fortran/C 代码绑定到 Python 的工具

    • numpy.core - 用于替代 Numeric 和 numarray 包的未来版本

    • numpy.lib - 额外实用函数

    • numpy.testing - 用于单元测试的 numpy 风格工具

    • 等等

  • SciPy — 一套用于 Python 的科学工具集。

本文档的目的是描述如何向 SciPy 中添加新工具。

SciPy 包的要求

SciPy 由名为 SciPy 包的 Python 包组成,通过 scipy 命名空间可以提供给 Python 用户使用。每个 SciPy 包可能包含其他 SciPy 包。因此,SciPy 目录树是具有任意深度和宽度的包树。任何 SciPy 包可能依赖于 NumPy 包,但对其他 SciPy 包的依赖应尽可能减少或为零。

一个 SciPy 包除了其源代码外,还包括以下文件和目录:

  • setup.py — 构建脚本
  • __init__.py — 包初始化器
  • tests/ — 单元测试目录

它们的内容如下所述。

setup.py 文件

为了将一个 Python 包添加到 SciPy,其构建脚本 (setup.py) 必须符合某些要求。最重要的要求是包定义一个 configuration(parent_package='',top_path=None) 函数,该函数返回一个适合传递给 numpy.distutils.core.setup(..) 的字典。为了简化构造此字典,numpy.distutils.misc_util 提供了下面描述的 Configuration 类。

SciPy 纯 Python 包示例

下面是一个纯 SciPy 包的最小 setup.py 文件示例:

#!/usr/bin/env python3
def configuration(parent_package='',top_path=None):
    from numpy.distutils.misc_util import Configuration
    config = Configuration('mypackage',parent_package,top_path)
    return config

if __name__ == "__main__":
    from numpy.distutils.core import setup
    #setup(**configuration(top_path='').todict())
    setup(configuration=configuration) 

configuration 函数的参数指定了父 SciPy 包的名称(parent_package)和主 setup.py 脚本的目录位置(top_path)。这些参数和当前包的名称应该传递给 Configuration 构造函数。

Configuration 构造函数有第四个可选参数,package_path,当包文件位于与 setup.py 文件所在目录不同的位置时可以使用。

剩余的Configuration参数都是初始化Configuration实例属性时将使用的关键字参数。通常,这些关键字与setup(..)函数所期望的关键字相同,例如,packages, ext_modules, data_files, include_dirs, libraries, headers, scripts, package_dir等。但是,不建议直接指定这些关键字参数,因为这些关键字参数的内容不会被处理或检查 SciPy 构建系统的一致性。

最后,Configuration具有.todict()方法,它将所有配置数据作为适合传递给setup(..)函数的字典返回。

Configuration实例属性

除了可以通过关键字参数指定给Configuration构造函数的属性之外,Configuration实例(我们以config表示)还具有以下属性,这些属性在编写设置脚本时可能会有用:

  • config.name - 当前软件包的完整名称。可以提取父软件包的名称作为config.name.split('.')

  • config.local_path - 指向当前setup.py文件的路径。

  • config.top_path - 指向主setup.py文件的路径。

Configuration实例方法

  • config.todict() — 返回适合传递给numpy.distutils.core.setup(..)函数的配置字典。

  • config.paths(*paths) --- 如有必要,将paths的项应用于``glob.glob(..)。修复相对于config.local_pathpaths项。

  • config.get_subpackage(subpackage_name,subpackage_path=None) — 返回子软件包配置的列表。在当前目录中查找名称为subpackage_name的子软件包,但也可以通过可选的subpackage_path参数指定路径。如果将subpackage_name指定为None,则子软件包的名称将采用subpackage_path的基本名称。任何用于子软件包名称的*都会按通配符进行展开。

  • config.add_subpackage(subpackage_name,subpackage_path=None) — 将 SciPy 子软件包配置添加到当前配置中。上面解释了参数的含义和用法,请参见config.get_subpackage()方法。

  • config.add_data_files(*files) — 将files添加到data_files列表的开头。如果files项是元组,则其第一个元素定义了数据文件相对于软件包安装目录的后缀,第二个元素指定了数据文件的路径。默认情况下,数据文件被复制到软件包安装目录下。例如,

    config.add_data_files('foo.dat',
                          ('fun',['gun.dat','nun/pun.dat','/tmp/sun.dat']),
                          'bar/car.dat'.
                          '/full/path/to/can.dat',
                          ) 
    

    将数据文件安装到以下位置

    <installation path of config.name package>/
      foo.dat
      fun/
        gun.dat
        pun.dat
        sun.dat
      bar/
        car.dat
      can.dat 
    

    数据文件的路径可以是一个不带参数并返回数据文件路径的函数 —— 当在构建软件包时生成数据文件时,这是非常有用的。(XXX:解释确切调用这些函数的步骤)

  • config.add_data_dir(data_path) — 递归地将data_path目录添加到data_files中。从data_path开始的整个目录树将被复制到包安装目录下。如果data_path是一个元组,则它的第一个元素定义了数据文件被复制的后缀,相对于包安装目录,第二个元素指定了数据目录的路径。默认情况下,数据目录将被复制到包安装目录下的data_path的基本名称下。例如,

    config.add_data_dir('fun')  # fun/ contains foo.dat bar/car.dat
    config.add_data_dir(('sun','fun'))
    config.add_data_dir(('gun','/full/path/to/fun')) 
    

    将数据文件安装到以下位置

    <installation path of config.name package>/
      fun/
         foo.dat
         bar/
            car.dat
      sun/
         foo.dat
         bar/
            car.dat
      gun/
         foo.dat
         bar/
            car.dat 
    
  • config.add_include_dirs(*paths) — 将paths添加到include_dirs列表的开头。这个列表对当前包的所有扩展模块可见。

  • config.add_headers(*files) — 将files添加到headers列表的开头。默认情况下,头文件将安装在<prefix>/include/pythonX.X/<config.name.replace('.','/')>/目录下。如果files项是一个元组,则它的第一个参数指定了相对于<prefix>/include/pythonX.X/路径的安装后缀。这是一个 Python distutils 方法;在 NumPy 和 SciPy 中应该使用config.add_data_files(*files)

  • config.add_scripts(*files) — 将files添加到scripts列表的开头。脚本将安装在<prefix>/bin/目录下。

  • config.add_extension(name,sources,**kw) — 创建并将一个Extension实例添加到ext_modules列表中。第一个参数name定义了扩展模块的名称,该扩展模块将安装在config.name包下。第二个参数是一个源列表。add_extension方法还接受将传递给Extension构造函数的关键字参数。允许的关键字列表如下:include_dirsdefine_macrosundef_macroslibrary_dirslibrariesruntime_library_dirsextra_objectsextra_compile_argsextra_link_argsexport_symbolsswig_optsdependslanguagef2py_optionsmodule_dirsextra_infoextra_f77_compile_argsextra_f90_compile_args

    请注意,config.paths方法适用于可能包含路径的所有列表。extra_info是一个字典或字典列表,其内容将追加到关键字参数。depends列表包含扩展模块源代码依赖的文件或目录路径。如果depends列表中的任何路径都比扩展模块新,那么模块将被重新构建。

    源列表可能包含函数(‘源生成器’),其模式为def <funcname>(ext, build_dir): return <source(s) or None>。如果funcname返回None,则不会生成任何源代码。如果所有源生成器处理后Extension实例没有源代码,那么不会构建扩展模块。这是有条件地定义扩展模块的推荐方法。源生成器函数由numpy.distutilsbuild_src子命令调用。

    例如,这是一个典型的源生成器函数:

    def generate_source(ext,build_dir):
        import os
        from distutils.dep_util import newer
        target = os.path.join(build_dir,'somesource.c')
        if newer(target,__file__):
            # create target file
        return target 
    

    第一个参数包含 Extension 实例,可以用于访问其属性,如dependssources等列表,并在构建过程中对其进行修改。第二个参数给出了一个构建目录的路径,在将文件写入磁盘时必须使用该目录。

  • config.add_library(name, sources, **build_info) — 向libraries列表添加一个库。允许的关键字参数有dependsmacrosinclude_dirsextra_compiler_argsf2py_optionsextra_f77_compile_argsextra_f90_compile_args。有关参数的更多信息,请参见.add_extension()方法。

  • config.have_f77c() — 如果 Fortran 77 编译器可用,则返回 True(即:简单的 Fortran 77 代码编译成功)。

  • config.have_f90c() — 如果 Fortran 90 编译器可用,则返回 True(即:简单的 Fortran 90 代码编译成功)。

  • config.get_version() — 返回当前包的版本字符串,如果无法检测到版本信息,则返回None。该方法扫描文件__version__.py<packagename>_version.pyversion.py__svn_version__.py以查找字符串变量version__version__<packagename>_version

  • config.make_svn_version_py() — 向data_files列表附加一个数据函数,该函数将生成__svn_version__.py文件到当前包目录。当 Python 退出时,将从源目录中删除该文件。

  • config.get_build_temp_dir() — 返回一个临时目录的路径。这是构建临时文件的地方。

  • config.get_distribution() — 返回 distutils 的Distribution实例。

  • config.get_config_cmd() — 返回numpy.distutils配置命令实例。

  • config.get_info(*names)

使用模板转换.src文件

NumPy distutils 支持自动转换命名为.src 的源文件。该功能可用于维护非常相似的代码块,只需要在块之间进行简单的更改。在设置的构建阶段,如果遇到名为.src 的模板文件,则会从模板构造一个名为的新文件,并将其放置在构建目录中以供使用。支持两种模板转换形式。第一种形式用于名为.ext.src 的文件,其中 ext 是一个已识别的 Fortran 扩展名(f、f90、f95、f77、for、ftn、pyf)。第二种形式用于所有其他情况。 ### Fortran 文件

此模板转换器将根据‘<…>’中的规则复制文件中所有的函数子程序块,名字中含有‘<…>’的。‘<…>’中以逗号分隔的单词的数量决定了块的重复次数。这些单词指示了在每个块中将重复规则‘<…>’替换为什么内容。块中的所有重复规则必须包含相同数量的逗号分隔的单词,以指示该块应该重复多少次。如果重复规则中的单词需要逗号、箭头或右箭头,则在其前面添加反斜杠‘ '。如果重复规则中的单词与‘ <index>’匹配,则会被替换为相同重复规范中的第个单词。重复规则有两种形式:命名和短形式。

命名的重复规则

命名的重复规则在一个块中多次使用相同重复集时很有用。它使用<rule1=item1, item2, item3,…, itemN>的格式指定,其中 N 是应该重复该块的次数。在每个块的重复中,整个表达式‘<…>’将首先替换为 item1,然后替换为 item2,以此类推,直到完成 N 次重复。一旦引入了命名的重复规范,相同的重复规则可以通过只引用名称(即)在当前块中使用。

短形式的重复规则

短形式的重复规则的格式为<item1, item2, item3, …, itemN>。该规则指定整个表达式‘<…>’应首先替换为 item1,然后替换为 item2,以此类推,直到完成 N 次重复。

预定义名称

可用的预定义命名重复规则如下:

  • <prefix=s,d,c,z>

  • <_c=s,d,c,z>

  • <_t=real, double precision, complex, double complex>

  • <ftype=real, double precision, complex, double complex>

  • <ctype=float, double, complex_float, complex_double>

  • <ftypereal=float, double precision, \0, \1>

  • <ctypereal=float, double, \0, \1>

其他文件

非 Fortran 文件使用单独的语法来定义应使用类似于 Fortran 特定重复的命名重复规则的模板块的变量扩展。

NumPy Distutils 预处理以自定义模板语言编写的 C 源文件(扩展名:.c.src)以生成 C 代码。@符号用于包装宏样式的变量,以实现可能描述(例如)一组数据类型的字符串替换机制。

模板语言块由/**begin repeat/**end repeat**/行进行界定,这些界定行也可以使用连续编号的界定行(如/**begin repeat1/**end repeat1**/)进行嵌套:

  1. /**begin repeat单独一行标志着应该重复的段的开始。

  2. 使用#name=item1, item2, item3, ..., itemN#定义命名变量扩展,并放置在连续的行上。这些变量会在每个重复块中被相应的词替换。同一重复块中的所有命名变量必须定义相同数量的词。

  3. 在为命名变量指定重复规则时,item*Nitem, item, ..., item重复 N 次的简写。此外,结合*N的括号可用于对应多个应该重复的项进行分组。因此,#name=(item1, item2)*4#等同于#name=item1, item2, item1, item2, item1, item2, item1, item2#

  4. 单独一行上的*/标记结束变量扩展命名。下一行是将使用命名规则重复的第一行。

  5. 在要重复的块内,应扩展的变量被指定为@name@

  6. 单独一行上的/**end repeat**/标记前一行为要重复的块的最后一行。

  7. NumPy C 源代码中的循环可能具有@TYPE@变量,用于字符串替换,预处理为具有多个字符串(如INTLONGUINTULONG等)的通常相同的循环。因此,@TYPE@样式语法通过模仿具有通用类型支持的语言来减少代码重复和维护负担。

以上规则在以下模板源示例中可能更清晰:

 1  /* TIMEDELTA to non-float types */
 2
 3  /**begin repeat 4 *
 5 * #TOTYPE = BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG,
 6 *           LONGLONG, ULONGLONG, DATETIME,
 7 *           TIMEDELTA#
 8 * #totype = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
 9 *           npy_long, npy_ulong, npy_longlong, npy_ulonglong,
10 *           npy_datetime, npy_timedelta#
11 */
12
13  /**begin repeat1 14 *
15 * #FROMTYPE = TIMEDELTA#
16 * #fromtype = npy_timedelta#
17 */
18  static  void
19  @FROMTYPE@_to_@TOTYPE@(void *input, void *output, npy_intp n,
20  void  *NPY_UNUSED(aip),  void  *NPY_UNUSED(aop))
21  {
22  const  @fromtype@ *ip = input;
23  @totype@ *op = output;
24
25  while  (n--)  {
26  *op++  =  (@totype@)*ip++;
27  }
28  }
29  /**end repeat1**/ 30
31  /**end repeat**/ 

通用类型 C 源文件的预处理(无论是 NumPy 本身还是使用 NumPy Distutils 的任何第三方包中的文件)由conv_template.py执行。在构建过程中由这些模块生成的特定类型 C 文件(扩展名:.c)已准备好进行编译。这种通用类型的形式也支持 C 头文件(预处理以生成.h文件)。

numpy.distutils.misc_util中的有用函数

  • get_numpy_include_dirs() — 返回 NumPy 基础包含目录的列表。NumPy 基础包含目录包含诸如numpy/arrayobject.hnumpy/funcobject.h等头文件。对于已安装的 NumPy,返回的列表长度为 1,但在构建 NumPy 时,列表可能包含更多目录,例如,numpy/base/setup.py文件生成并被numpy头文件使用的config.h文件路径。

  • append_path(prefix,path) — 智能地将path附加到prefix

  • gpaths(paths, local_path='') — 对路径应用 glob 并在需要时添加local_path前缀。

  • njoin(*path) — 连接路径名组件+将/分隔路径转换为os.sep分隔路径并解析路径中的...。例如,njoin('a',['b','./c'],'..','g') -> os.path.join('a','b','g')

  • minrelpath(path) — 解析path中的点号。

  • rel_path(path, parent_path) — 返回相对于parent_pathpath

  • def get_cmd(cmdname,_cache={}) — 返回numpy.distutils命令实例。

  • all_strings(lst)

  • has_f_sources(sources)

  • has_cxx_sources(sources)

  • filter_sources(sources) — 返回c_sources, cxx_sources, f_sources, fmodule_sources

  • get_dependencies(sources)

  • is_local_src_dir(directory)

  • get_ext_source_files(ext)

  • get_script_files(scripts)

  • get_lib_source_files(lib)

  • get_data_files(data)

  • dot_join(*args) — 用点连接非零参数。

  • get_frame(level=0) — 返回给定级别调用堆栈中的帧对象。

  • cyg2win32(path)

  • mingw32() — 在使用 mingw32 环境时返回True

  • terminal_has_colors(), red_text(s), green_text(s), yellow_text(s), blue_text(s), cyan_text(s)

  • get_path(mod_name,parent_path=None) — 在给定时,返回相对于 parent_path 的模块路径。也处理__main____builtin__模块。

  • allpath(name) — 在name中将/替换为os.sep

  • cxx_ext_match, fortran_ext_match, f90_ext_match, f90_module_name_match

numpy.distutils.system_info 模块

  • get_info(name,notfound_action=0)

  • combine_paths(*args,**kws)

  • show_all()

numpy.distutils.cpuinfo 模块

  • cpuinfo

numpy.distutils.log 模块

  • set_verbosity(v)

numpy.distutils.exec_command 模块

  • get_pythonexe()

  • find_executable(exe, path=None)

  • exec_command( command, execute_in='', use_shell=None, use_tee=None, **env )

__init__.py 文件

典型 SciPy __init__.py 的头部是:

"""
Package docstring, typically with a brief description and function listing.
"""

# import functions into module namespace
from .subpackage import *
...

__all__ = [s for s in dir() if not s.startswith('_')]

from numpy.testing import Tester
test = Tester().test
bench = Tester().bench 

NumPy Distutils 中的额外功能

在 setup.py 脚本中为库指定 config_fc 选项

可以在 setup.py 脚本中指定 config_fc 选项。例如,使用

config.add_library(‘library’,

sources=[…], config_fc={‘noopt’😦file,1)})

将编译 library 源文件时不使用优化标志。

建议只指定那些与编译器无关的 config_fc 选项。

从源代码中获取额外的 Fortran 77 编译器选项

一些旧的 Fortran 代码需要特殊的编译器选项才能正确工作。为了指定每个源文件的编译器选项,numpy.distutils Fortran 编译器寻找以下模式:

CF77FLAGS(<fcompiler type>) = <fcompiler f77flags> 

在源代码的前 20 行中,并针对指定类型的 fcompiler 使用 f77flags(第一个字符 C 可选)。

TODO: 这个功能也可以很容易地扩展到 Fortran 90 代码上。如果您需要这样的功能,请告诉我们。

SciPy 结构

当前 SciPy 项目包括两个包:

  • NumPy — 提供类似以下包:

    • numpy.distutils - Python distutils 的扩展

    • numpy.f2py - 一个将 Fortran/C 代码绑定到 Python 的工具

    • numpy.core - 取代 Numeric 和 numarray 包的未来包裹

    • numpy.lib - 额外的实用函数

    • numpy.testing - 类似于 numpy 的单元测试工具

  • SciPy — 为 Python 提供的一批科学工具。

本文旨在描述如何向 SciPy 添加新工具。

SciPy 包的要求

SciPy 由 Python 包组成,称为 SciPy 包,通过scipy名称空间提供给 Python 用户。每个 SciPy 包可能包含其他 SciPy 包。以此类推。因此,SciPy 目录树是具有任意深度和宽度的包树。任何 SciPy 包可能依赖于 NumPy 包,但对其他 SciPy 包的依赖应保持最小或零。

除了源文件之外,SciPy 包还包含以下文件和目录:

  • setup.py — 构建脚本
  • __init__.py — 包初始化文件
  • tests/ — 单元测试目录

它们的内容如下。

setup.py文件

要将 Python 包添加到 SciPy,其构建脚本(setup.py)必须满足一定的要求。最重要的要求是该包定义一个返回适合传递给numpy.distutils.core.setup(..)的字典的configuration(parent_package='',top_path=None)函数。为了简化构建此字典的过程,numpy.distutils.misc_util提供了下面描述的Configuration类。

SciPy 纯 Python 包示例

以下是一个纯 SciPy 包的最小setup.py文件示例:

#!/usr/bin/env python3
def configuration(parent_package='',top_path=None):
    from numpy.distutils.misc_util import Configuration
    config = Configuration('mypackage',parent_package,top_path)
    return config

if __name__ == "__main__":
    from numpy.distutils.core import setup
    #setup(**configuration(top_path='').todict())
    setup(configuration=configuration) 

configuration函数的参数指定父 SciPy 包的名称(parent_package)和主setup.py脚本的目录位置(top_path)。这些参数,连同当前包的名称,应传递给Configuration构造函数。

Configuration构造函数有一个第四个可选参数package_path,用于当包文件位于不同于setup.py文件目录的位置时使用。

剩余的Configuration参数都是将用于初始化Configuration实例属性的关键字参数。通常,这些关键字与setup(..)函数所期望的关键字相同,例如packagesext_modulesdata_filesinclude_dirslibrariesheadersscriptspackage_dir等。但是,不建议直接指定这些关键字,因为这些关键字参数的内容不会被处理或检查 SciPy 构建系统的一致性。

最后,Configuration有一个.todict()方法,将所有配置数据作为适合传递给setup(..)函数的字典返回。

Configuration实例属性

除了可以通过关键字参数指定的属性外,Configuration实例(我们将其标记为config)具有以下对于编写安装脚本很有用的属性:

  • config.name - 当前包的完整名称。可以提取父包的名称为config.name.split('.')

  • config.local_path - 当前setup.py文件的路径位置。

  • config.top_path - 主setup.py文件的路径位置。

Configuration实例方法

  • config.todict() — 返回适合传递给numpy.distutils.core.setup(..)函数的配置字典。

  • config.paths(*paths) --- 如果必要,对paths的项目应用glob.glob(..)。修复相对于config.local_pathpaths`项目。

  • config.get_subpackage(subpackage_name,subpackage_path=None) — 返回子包配置的列表。在当前目录下查找名为subpackage_name的子包,但也可以通过可选的subpackage_path参数指定路径。如果subpackage_name指定为None,则子包名称将使用subpackage_path的基本名称。任何用于子包名称的*都会被扩展为通配符。

  • config.add_subpackage(subpackage_name,subpackage_path=None) — 向当前配置添加 SciPy 子包配置。解释参数的含义和用法如上所述,请参阅config.get_subpackage()方法。

  • config.add_data_files(*files) — 将files添加到data_files列表的开头。如果files项目是一个元组,则其第一个元素定义了将数据文件复制到包安装目录的后缀,第二个元素指定了数据文件的路径。默认情况下,数据文件将复制到包安装目录下。例如,

    config.add_data_files('foo.dat',
                          ('fun',['gun.dat','nun/pun.dat','/tmp/sun.dat']),
                          'bar/car.dat'.
                          '/full/path/to/can.dat',
                          ) 
    

    将数据文件安装到以下位置

    <installation path of config.name package>/
      foo.dat
      fun/
        gun.dat
        pun.dat
        sun.dat
      bar/
        car.dat
      can.dat 
    

    数据文件的路径可以是一个不带参数并返回路径(s)到数据文件的函数——当构建包时生成数据文件时,这是一个有用的功能(XXX:具体解释这个函数什么时候被调用)

  • config.add_data_dir(data_path) — 递归地将目录data_path添加到data_files中。从data_path开始的整个目录树将在包安装目录下复制。如果data_path是一个元组,则其第一个元素定义了复制数据文件的后缀,相对于包安装目录,第二个元素指定了数据目录的路径。默认情况下,数据目录被复制到包安装目录下,以data_path的基本名称命名。例如,

    config.add_data_dir('fun')  # fun/ contains foo.dat bar/car.dat
    config.add_data_dir(('sun','fun'))
    config.add_data_dir(('gun','/full/path/to/fun')) 
    

    将数据文件安装到以下位置

    <installation path of config.name package>/
      fun/
         foo.dat
         bar/
            car.dat
      sun/
         foo.dat
         bar/
            car.dat
      gun/
         foo.dat
         bar/
            car.dat 
    
  • config.add_include_dirs(*paths) — 将paths添加到include_dirs列表的开头。这个列表将对当前包的所有扩展模块可见。

  • config.add_headers(*files) — 将files添加到headers列表的开头。默认情况下,头文件将安装在<prefix>/include/pythonX.X/<config.name.replace('.','/')>/目录下。如果files项目是一个元组,那么它的第一个参数指定相对于<prefix>/include/pythonX.X/路径的安装后缀。这是一个 Python distutils 方法;在 NumPy 和 SciPy 中,建议使用config.add_data_files(*files)

  • config.add_scripts(*files) — 将files添加到scripts列表的开头。脚本将安装在<prefix>/bin/目录下。

  • config.add_extension(name,sources,**kw) — 创建并将一个 Extension 实例添加到 ext_modules 列表中。第一个参数 name 定义了扩展模块的名称,该模块将安装在 config.name 包下。第二个参数是一个源列表。add_extension 方法还接受传递给 Extension 构造函数的关键字参数。允许的关键字列表如下:include_dirsdefine_macrosundef_macroslibrary_dirslibrariesruntime_library_dirsextra_objectsextra_compile_argsextra_link_argsexport_symbolsswig_optsdependslanguagef2py_optionsmodule_dirsextra_infoextra_f77_compile_argsextra_f90_compile_args

    请注意,config.paths 方法适用于可能包含路径的所有列表。extra_info 是一个字典或字典列表,其内容将附加到关键字参数中。depends 列表包含了扩展模块的源文件依赖的文件或目录路径。如果 depends 列表中的任何路径新于扩展模块,则将重新构建该模块。

    源列表可能包含具有模式 def <funcname>(ext, build_dir): return <source(s) or None> 的函数(‘源生成器’)。 如果 funcname 返回 None,则不会生成任何源。如果 Extension 实例在处理所有源生成器后没有任何源,那么不会构建扩展模块。这是有条件地定义扩展模块的推荐方法。源生成器函数由 numpy.distutilsbuild_src 子命令调用。

    例如,这是一个典型的源生成器函数示例:

    def generate_source(ext,build_dir):
        import os
        from distutils.dep_util import newer
        target = os.path.join(build_dir,'somesource.c')
        if newer(target,__file__):
            # create target file
        return target 
    

    第一个参数包含了 Extension 实例,可以用于访问其属性,如 dependssources 等列表,并在构建过程中修改它们。第二个参数提供了一个构建目录的路径,在创建文件到磁盘时必须使用该路径。

  • config.add_library(name, sources, **build_info) — 将库添加到 libraries 列表中。允许的关键字参数包括 dependsmacrosinclude_dirsextra_compiler_argsf2py_optionsextra_f77_compile_argsextra_f90_compile_args。有关参数的更多信息,请参阅.add_extension() 方法。

  • config.have_f77c() — 如果 Fortran 77 编译器可用(即:简单的 Fortran 77 代码编译成功),则返回 True。

  • config.have_f90c() — 如果 Fortran 90 编译器可用(即:简单的 Fortran 90 代码编译成功),则返回 True。

  • config.get_version() — 返回当前包的版本字符串,如果无法检测到版本信息,则返回 None。该方法扫描文件 __version__.py<packagename>_version.pyversion.py__svn_version__.py,以查找字符串变量 version__version__<packagename>_version

  • config.make_svn_version_py() — 向data_files列表添加一个数据函数,该函数将生成__svn_version__.py文件到当前包目录。Python 退出时,该文件将从源目录中删除。

  • config.get_build_temp_dir() — 返回临时目录路径。这是应该构建临时文件的地方。

  • config.get_distribution() — 返回 distutils Distribution 实例。

  • config.get_config_cmd() — 返回 numpy.distutils 配置命令实例。

  • config.get_info(*names)

使用模板转换.src文件

NumPy distutils 支持自动转换命名为.src 的源文件。这个功能可用于在块之间保持非常相似的代码,只需要进行简单的更改。在设置的构建阶段期间,如果遇到名为.src 的模板文件,将从模板构造一个名为的新文件,并将其放置在构建目录中以供使用。支持两种模板转换形式。第一种形式适用于文件名为.ext.src,其中 ext 是一个已识别的 Fortran 扩展名(f,f90,f95,f77,for,ftn,pyf)。第二种形式用于所有其他情况。### Fortran 文件

此模板转换器将根据‘<…>’中的规则,复制文件中所有的函数子例程块,并以包含‘<…>’的名称来重复。‘<…>’中用逗号分隔的单词的数量决定了块被重复的次数。这些单词指示了在每个块中‘<…>’应该用什么替换。一个块中的所有重复规则必须包含相同数量的逗号分隔的单词,表明这个块应该被重复的次数。如果重复规则中的单词需要有逗号,左箭头或右箭头,那么在其前面加上反斜杠' '。如果重复规则中的单词匹配‘<index>’,那么它将被替换为相同重复规范中的第个单词。重复规则有两种形式:命名和简短。

命名重复规则

当同一组重复必须多次在一个块中使用时,命名重复规则非常有用。它使用<rule1=item1, item2, item3,…, itemN>来指定,其中 N 是块应该重复的次数。在块的每次重复中,整个表达式‘<…>’首先会被 item1 替换,然后被 item2 替换,依此类推,直到完成 N 次重复。一旦引入了命名重复规范,就可以通过只引用名称(即<规则 1>)在当前块中使用相同的重复规则。

简短重复规则

简短重复规则看起来像<item1, item2, item3, …, itemN>。规则指定整个表达式‘<…>’应首先用 item1 替换,然后用 item2 替换,依此类推,直到 N 次重复完成。

预定义名称

以下是可用的预定义命名重复规则:

  • <prefix=s,d,c,z>

  • <_c=s,d,c,z>

  • <_t=real, double precision, complex, double complex>

  • <ftype=real, double precision, complex, double complex>

  • <ctype=float, double, complex_float, complex_double>

  • <ftypereal=float, double precision, \0, \1>

  • <ctypereal=float, double, \0, \1>

其他文件

非 Fortran 文件使用单独的语法来定义应使用类似于 Fortran 特定重复规则的变量扩展的模板块。

NumPy Distutils 对使用自定义模板语言编写的 C 源文件(扩展名:.c.src)进行预处理以生成 C 代码。@符号用于包装宏样式的变量,以提供描述(例如)一组数据类型的字符串替换机制。

模板语言块由/**begin repeat/**end repeat**/行界定,这些行也可以使用连续编号的界定行进行嵌套,例如/**begin repeat1/**end repeat1**/

  1. 单独一行上的/**begin repeat标记了应重复的段的开始。

  2. 使用#name=item1, item2, item3, ..., itemN#定义命名变量扩展,并将其放置在连续的行上。这些变量在每个重复块中与相应的单词替换。同一重复块中的所有命名变量必须定义相同数量的单词。

  3. 在为命名变量指定重复规则时,item*N表示item, item, ..., item重复 N 次的简写。此外,结合*N的括号可以用于分组多个应该重复的项。因此,#name=(item1, item2)*4#相当于#name=item1, item2, item1, item2, item1, item2, item1, item2#

  4. 单独一行的*/标记了变量扩展命名的结束。下一行是将使用命名规则重复的第一行。

  5. 在要重复的块内,指定要展开的变量为@name@

  6. 单独一行的/**end repeat**/标记了前一行作为要重复块的最后一行。

  7. NumPy C 源代码中的循环可能具有@TYPE@变量,用于字符串替换,该变量经预处理后成为多个完全相同的循环,其中包含INTLONGUINTULONG等多个字符串。因此,@TYPE@样式的语法通过模仿具有通用类型支持的语言来减少代码重复和维护负担。

以下是上述规则在以下模板源示例中更为明确的示例:

 1  /* TIMEDELTA to non-float types */
 2
 3  /**begin repeat 4 *
 5 * #TOTYPE = BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG,
 6 *           LONGLONG, ULONGLONG, DATETIME,
 7 *           TIMEDELTA#
 8 * #totype = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
 9 *           npy_long, npy_ulong, npy_longlong, npy_ulonglong,
10 *           npy_datetime, npy_timedelta#
11 */
12
13  /**begin repeat1 14 *
15 * #FROMTYPE = TIMEDELTA#
16 * #fromtype = npy_timedelta#
17 */
18  static  void
19  @FROMTYPE@_to_@TOTYPE@(void *input, void *output, npy_intp n,
20  void  *NPY_UNUSED(aip),  void  *NPY_UNUSED(aop))
21  {
22  const  @fromtype@ *ip = input;
23  @totype@ *op = output;
24
25  while  (n--)  {
26  *op++  =  (@totype@)*ip++;
27  }
28  }
29  /**end repeat1**/ 30
31  /**end repeat**/ 

对于通用类型的 C 源文件(无论是在 NumPy 本身还是在使用 NumPy Distutils 的任何第三方包中),都使用conv_template.py进行预处理。在构建过程中,这些模块生成的特定类型的 C 文件(扩展名:.c)已经准备好编译了。此类通用类型也支持 C 头文件(预处理为.h文件)。

numpy.distutils.misc_util中的实用函数

  • get_numpy_include_dirs() — 返回 NumPy 基本包含目录列表。NumPy 基本包含目录包含诸如numpy/arrayobject.hnumpy/funcobject.h等头文件。对于已安装的 NumPy,返回的列表长度为 1,但构建 NumPy 时,该列表可能包含更多目录,例如,numpy/base/setup.py文件生成并被numpy头文件使用的config.h文件路径��

  • append_path(prefix,path) — 将path智能地附加到prefix

  • gpaths(paths, local_path='') — 对路径应用 glob,并在必要时添加local_path前缀。

  • njoin(*path) — 连接路径名组件+将/分隔的路径转换为os.sep分隔的路径并从路径中解析...。例如,njoin('a',['b','./c'],'..','g') -> os.path.join('a','b','g')

  • minrelpath(path) — 解析path中的点。

  • rel_path(path, parent_path) — 返回相对于parent_pathpath

  • def get_cmd(cmdname,_cache={}) — 返回numpy.distutils命令实例。

  • all_strings(lst)

  • has_f_sources(sources)

  • has_cxx_sources(sources)

  • filter_sources(sources) — 返回c_sources, cxx_sources, f_sources, fmodule_sources

  • get_dependencies(sources)

  • is_local_src_dir(directory)

  • get_ext_source_files(ext)

  • get_script_files(scripts)

  • get_lib_source_files(lib)

  • get_data_files(data)

  • dot_join(*args) — 用点连接非零参数。

  • get_frame(level=0) — 返回调用栈中给定级别的 frame 对象。

  • cyg2win32(path)

  • mingw32() — 在使用 mingw32 环境时返回True

  • terminal_has_colors(), red_text(s), green_text(s), yellow_text(s), blue_text(s), cyan_text(s)

  • get_path(mod_name,parent_path=None) — 在给定时返回模块相对于 parent_path 的路径。还处理__main____builtin__模块。

  • allpath(name) — 在name中将/替换为os.sep

  • cxx_ext_match, fortran_ext_match, f90_ext_match, f90_module_name_match

numpy.distutils.system_info模块

  • get_info(name,notfound_action=0)

  • combine_paths(*args,**kws)

  • show_all()

numpy.distutils.cpuinfo模块

  • cpuinfo

numpy.distutils.log模块

  • set_verbosity(v)

numpy.distutils.exec_command模块

  • get_pythonexe()

  • find_executable(exe, path=None)

  • exec_command( command, execute_in='', use_shell=None, use_tee=None, **env )

SciPy 纯 Python 软件包示例

下面是用于纯 SciPy 软件包的最小setup.py文件示例:

#!/usr/bin/env python3
def configuration(parent_package='',top_path=None):
    from numpy.distutils.misc_util import Configuration
    config = Configuration('mypackage',parent_package,top_path)
    return config

if __name__ == "__main__":
    from numpy.distutils.core import setup
    #setup(**configuration(top_path='').todict())
    setup(configuration=configuration) 

configuration函数的参数指定父 SciPy 软件包的名称(parent_package)和主setup.py脚本的目录位置(top_path)。这些参数以及当前软件包的名称应传递给Configuration构造函数。

Configuration构造函数有第四个可选参数package_path,可在软件包文件位于与setup.py文件目录不同的位置时使用。

剩余的Configuration参数都是Configuration实例属性的关键字参数的初始化值。通常,这些关键字与setup(..)函数期望的关键字是相同的,例如,packagesext_modulesdata_filesinclude_dirslibrariesheadersscriptspackage_dir等。然而,不建议直接指定这些关键字,因为这些关键字参数的内容不会被处理或检查 SciPy 构建系统的一致性。

最后,Configuration有一个.todict()方法,它返回所有配置数据,以字典的形式适合传递给setup(..)函数。

Configuration实例的属性

除了可以通过Configuration构造函数的关键参数指定的属性之外,Configuration实例(假设为config)还有以下属性,可以在编写设置脚本时很有用:

  • config.name - 当前软件包的完整名称。父软件包的名称可以通过config.name.split('.')来提取。

  • config.local_path - 当前setup.py文件的路径。

  • config.top_path - 主setup.py文件的路径。

Configuration实例的方法

  • config.todict() — 返回适合传递给numpy.distutils.core.setup(..)函数的配置字典。

  • config.paths(*paths) --- 如果有必要,对paths的项应用``glob.glob(..)。修复相对于config.local_pathpaths项。

  • config.get_subpackage(subpackage_name,subpackage_path=None) — 返回子软件包配置的列表。子软件包在当前目录下寻找,名称为subpackage_name,但路径也可以通过可选的subpackage_path参数指定。如果subpackage_name指定为None,则子软件包名称将取subpackage_path的基本名称。任何用于子软件包名称的*都会被扩展为通配符。

  • config.add_subpackage(subpackage_name,subpackage_path=None) — 将 SciPy 子软件包配置添加到当前配置。关于参数的意义和用法已在上文中解释过,参见config.get_subpackage()方法。

  • config.add_data_files(*files) — 将files加入data_files列表的最前面。如果files是一个元组,则其第一个元素定义了数据文件的后缀,相对于软件包安装目录的位置,第二个元素指定了数据文件的路径。默认情况下,数据文件将被复制到软件包安装目录下。例如,

    config.add_data_files('foo.dat',
                          ('fun',['gun.dat','nun/pun.dat','/tmp/sun.dat']),
                          'bar/car.dat'.
                          '/full/path/to/can.dat',
                          ) 
    

    将数据文件安装到以下位置

    <installation path of config.name package>/
      foo.dat
      fun/
        gun.dat
        pun.dat
        sun.dat
      bar/
        car.dat
      can.dat 
    

    数据文件的路径可以是一个不带参数并返回路径的函数 —— 这在生成软件包时生成数据文件时非常有用。(XXX:解释一下什么时候确切地调用这个函数)

  • config.add_data_dir(data_path) — 递归地将目录data_path添加到data_files中。从data_path开始的整个目录树将被复制到包安装目录下。 如果data_path是一个元组,那么它的第一个元素定义了将数据文件复制到的后缀的相对于包安装目录的位置,第二个元素指定了数据目录的路径。默认情况下,数据目录被复制到基础data_path的包安装目录下。例如,

    config.add_data_dir('fun')  # fun/ contains foo.dat bar/car.dat
    config.add_data_dir(('sun','fun'))
    config.add_data_dir(('gun','/full/path/to/fun')) 
    

    将数据文件安装到以下位置

    <installation path of config.name package>/
      fun/
         foo.dat
         bar/
            car.dat
      sun/
         foo.dat
         bar/
            car.dat
      gun/
         foo.dat
         bar/
            car.dat 
    
  • config.add_include_dirs(*paths) — 将paths添加到include_dirs列表的开头。这个列表将对当前包的所有扩展模块可见。

  • config.add_headers(*files) — 将files添加到headers列表的开头。默认情况下,头文件将安装在<prefix>/include/pythonX.X/<config.name.replace('.','/')>/目录下。 如果files项是一个元组,那么它的第一个参数指定了相对于<prefix>/include/pythonX.X/路径的安装后缀。 这是一个 Python distutils 方法;NumPy 和 SciPy 不鼓励使用它,而是使用config.add_data_files(*files)

  • config.add_scripts(*files) — 将files添加到scripts列表的开头。脚本将安装在<prefix>/bin/目录下。

  • config.add_extension(name,sources,**kw) — 创建并将一个Extension实例添加到ext_modules列表中。第一个参数name定义了扩展模块的名称,该模块将安装在config.name包下。第二个参数是一个来源列表。 add_extension方法还接受传递给Extension构造函数的关键字参数。允许的关键字参数列表如下:include_dirsdefine_macrosundef_macroslibrary_dirslibrariesruntime_library_dirsextra_objectsextra_compile_argsextra_link_argsexport_symbolsswig_optsdependslanguagef2py_optionsmodule_dirsextra_infoextra_f77_compile_argsextra_f90_compile_args

    注意,config.paths 方法应用于所有可能包含路径的列表。extra_info 是一个字典或字典列表,其内容将附加到关键字参数中。列表depends包含到扩展模块源的文件或目录的路径。如果depends列表中的任何路径都比扩展模块新,那么模块将被重新构建。

    来源列表可能包含函数(‘源生成器’),其模式为def <funcname>(ext, build_dir): return <source(s) or None>。如果funcname返回None,则不会生成任何源。如果Extension实例在处理所有源生成器后没有源,那么将不会构建任何扩展模块。这是有条件地定义扩展模块的推荐方式。源生成器函数由numpy.distutilsbuild_src子命令调用。

    例如,这是一个典型的源生成器函数:

    def generate_source(ext,build_dir):
        import os
        from distutils.dep_util import newer
        target = os.path.join(build_dir,'somesource.c')
        if newer(target,__file__):
            # create target file
        return target 
    

    第一个参数包含 Extension 实例,可以用于访问其属性,如dependssources等列表,并在构建过程中修改它们。第二个参数提供了一个构建目录的路径,必须在将文件写入磁盘时使用。

  • config.add_library(name, sources, **build_info) — 将库添加到libraries列表中。允许的关键字参数有dependsmacrosinclude_dirsextra_compiler_argsf2py_optionsextra_f77_compile_argsextra_f90_compile_args。有关参数的更多信息,请参见.add_extension()方法。

  • config.have_f77c() — 如果 Fortran 77 编译器可用,则返回 True(即:简单的 Fortran 77 代码编译成功)。

  • config.have_f90c() — 如果 Fortran 90 编译器可用,则返回 True(即:简单的 Fortran 90 代码编译成功)。

  • config.get_version() — 返回当前包的版本字符串,如果无法检测到版本信息,则返回None。该方法扫描文件__version__.py<packagename>_version.pyversion.py__svn_version__.py查找字符串变量version__version__<packagename>_version

  • config.make_svn_version_py() — 在data_files列表中追加一个数据函数,该函数将生成__svn_version__.py文件到当前包目录。该文件将在 Python 退出时从源目录中删除。

  • config.get_build_temp_dir() — 返回临时目录的路径。这是构建临时文件的位置。

  • config.get_distribution() — 返回 distutils Distribution实例。

  • config.get_config_cmd() — 返回numpy.distutils配置命令实例。

  • config.get_info(*names)

使用模板转换.src文件

NumPy distutils 支持自动转换以.src结尾的源文件。该功能可用于保留在块之间仅需进行简单更改的非常相似代码块。在设置的构建阶段,如果遇到名为<somefile>.src的模板文件,则将从模板构造一个新文件<somefile>并将其放置在构建目录中以供使用。支持两种模板转换形式。第一种形式用于以扩展名(f、f90、f95、f77、for、ftn、pyf)结尾的文件。第二种形式用于所有其他情况。

Fortran 文件

此模板转换器将根据‘<…>’中的规则,复制文件中所有函数子例程块的名称中包含‘<…>’的块。‘<...>’中以逗号分隔的单词数确定块重复的次数。这些单词表示每个块中应该用重复规则‘<...>’替换的内容。块中的所有重复规则必须包含相同数量的逗号分隔的单词,表示该块应重复的次数。如果重复规则中的单词需要逗号、左箭头或右箭头,则用反斜杠‘ '’在前面加上它。如果重复规则中的单词与‘ <index>’匹配,则它将被替换为相同重复规范中索引号-th 单词。重复规则有两种形式:命名和缩写。

命名重复规则

当同一组重复必须在块中多次使用时,命名重复规则非常有用。它使用<rule1=item1, item2, item3,…, itemN>来指定,其中 N 是应重复块的次数。在每次重复块时,整个表达式‘<...>’将首先替换为 item1,然后替换为 item2,依此类推,直到完成 N 次重复。一旦引入了一个命名重复规则,同一重复规则可以通过仅指定名称(即在当前块中使用。

缩写重复规则

缩写重复规则看起来像<item1, item2, item3, …, itemN>。该规则指定整个表达式‘<...>’应首先替换为 item1,然后替换为 item2,依此类推,直到完成 N 次重复。

预定义名称

下面列出了可用的预定义命名重复规则:

  • <prefix=s,d,c,z>

  • <_c=s,d,c,z>

  • <_t=实数, 双精度, 复数, 双精度复数>

  • <ftype=实数, 双精度, 复数, 双精度复数>

  • <ctype=浮点数, 双精度, 复数, 双精度复数>

  • <ftypereal=浮点数, 双精度, \0, \1>

  • <ctypereal=浮点数, 双精度, \0, \1>

命名重复规则

当同一组重复必须在块中多次使用时,命名重复规则非常有用。它使用<rule1=item1, item2, item3,…, itemN>来指定,其中 N 是应重复块的次数。在每次重复块时,整个表达式‘<...>’将首先替换为 item1,然后替换为 item2,依此类推,直到完成 N 次重复。一旦引入了一个命名重复规则,同一重复规则可以通过仅指定名称(即在当前块中使用。

缩写重复规则

缩写重复规则看起来像<item1, item2, item3, …, itemN>。该规则指定整个表达式‘<...>’应首先替换为 item1,然后替换为 item2,依此类推,直到完成 N 次重复。

预定义名称

下面列出了��用的预定义命名重复规则:

  • <prefix=s,d,c,z>

  • <_c=s,d,c,z>

  • <_t=实数, 双精度, 复数, 双精度复数>

  • <ftype=实数, 双精度, 复数, 双精度复数>

  • <ctype=float, double, complex_float, complex_double>

  • <ftypereal=float, double precision, \0, \1>

  • <ctypereal=float, double, \0, \1>

其他文件

非 Fortran 文件使用单独的语法来定义应使用类似于 Fortran 特定重复的命名重复规则的模板块。

NumPy Distutils 预处理用自定义模板语言编写的 C 源文件(扩展名:.c.src)以生成 C 代码。@符号用于包装宏风格变量,以实现描述(例如)一组数据类型的字符串替换机制。

模板语言块由/**begin repeat/**end repeat**/行界定,也可以使用连续编号的界定行进行嵌套,如/**begin repeat1/**end repeat1**/

  1. 单独一行上的/**begin repeat标志着应重复的段的开始。

  2. 使用#name=item1, item2, item3, ..., itemN#定义命名变量扩展,并放置在连续行上。这些变量将在每个重复块中与相应的单词替换。同一重复块中的所有命名变量必须定义相同数量的单词。

  3. 在指定命名变量的重复规则时,item*N表示item, item, ..., item重复 N 次。此外,结合*N的括号可以用于分组多个应重复的项目。因此,#name=(item1, item2)*4#等同于#name=item1, item2, item1, item2, item1, item2, item1, item2#

  4. 单独一行上的*/标志着变量扩展命名的结束。接下来的一行将是使用命名规则重复的第一行。

  5. 在应重复的块内,要扩展的变量被指定为@name@

  6. 单独一行上的/**end repeat**/标记着前一行作为应重复的块的最后一行。

  7. NumPy C 源代码中的循环可能有一个@TYPE@变量,用于字符串替换,它经过预处理后将成为几个其他相同的循环,带有诸如INTLONGUINTULONG等多个字符串。因此,@TYPE@样式的语法通过模仿具有通用类型支持的语言来减少代码重复和维护负担。

以上规则在以下模板源示例中可能更清晰:

 1  /* TIMEDELTA to non-float types */
 2
 3  /**begin repeat 4 *
 5 * #TOTYPE = BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG,
 6 *           LONGLONG, ULONGLONG, DATETIME,
 7 *           TIMEDELTA#
 8 * #totype = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
 9 *           npy_long, npy_ulong, npy_longlong, npy_ulonglong,
10 *           npy_datetime, npy_timedelta#
11 */
12
13  /**begin repeat1 14 *
15 * #FROMTYPE = TIMEDELTA#
16 * #fromtype = npy_timedelta#
17 */
18  static  void
19  @FROMTYPE@_to_@TOTYPE@(void *input, void *output, npy_intp n,
20  void  *NPY_UNUSED(aip),  void  *NPY_UNUSED(aop))
21  {
22  const  @fromtype@ *ip = input;
23  @totype@ *op = output;
24
25  while  (n--)  {
26  *op++  =  (@totype@)*ip++;
27  }
28  }
29  /**end repeat1**/ 30
31  /**end repeat**/ 

通用类型化 C 源文件的预处理(无论是在 NumPy 本身中还是在使用 NumPy Distutils 的任何第三方包中)由conv_template.py执行。在构建过程中由这些模块生成的特定类型的 C 文件(扩展名:.c)可供编译。这种通用类型化也适用于 C 头文件(预处理以生成.h文件)。

numpy.distutils.misc_util中的有用函数

  • get_numpy_include_dirs() — 返回 NumPy 基本包含目录的列表。NumPy 基本包含目录包含诸如numpy/arrayobject.hnumpy/funcobject.h等头文件。对于已安装的 NumPy,返回的列表长度为 1,但构建 NumPy 时,列表可能包含更多目录,例如,由numpy/base/setup.py生成并由numpy头文件使用的config.h文件的路径。

  • append_path(prefix,path) — 将path智能添加到prefix上。

  • gpaths(paths, local_path='') — 对路径应用 glob,并在需要时在前面添加local_path

  • njoin(*path) — 将路径名组件联接在一起,将以/分隔的路径转换为os.sep分隔的路径,并解析路径中的...。例如njoin('a',['b','./c'],'..','g') -> os.path.join('a','b','g')

  • minrelpath(path) — 解析path中的点。

  • rel_path(path, parent_path) — 返回相对于parent_pathpath

  • def get_cmd(cmdname,_cache={}) — 返回numpy.distutils命令实例。

  • all_strings(lst)

  • has_f_sources(sources)

  • has_cxx_sources(sources)

  • filter_sources(sources) — 返回c_sources, cxx_sources, f_sources, fmodule_sources

  • get_dependencies(sources)

  • is_local_src_dir(directory)

  • get_ext_source_files(ext)

  • get_script_files(scripts)

  • get_lib_source_files(lib)

  • get_data_files(data)

  • dot_join(*args) — 用点联接非零参数。

  • get_frame(level=0) — 根据指定的 level 从调用栈返回 frame 对象。

  • cyg2win32(path)

  • mingw32() — 在使用 mingw32 环境时返回True

  • terminal_has_colors(), red_text(s), green_text(s), yellow_text(s), blue_text(s), cyan_text(s)

  • get_path(mod_name,parent_path=None) — 在给定的 parent_path 下返回模块的路径。还处理__main____builtin__模块。

  • allpath(name) — 将name中的/替换为os.sep

  • cxx_ext_match, fortran_ext_match, f90_ext_match, f90_module_name_match

numpy.distutils.system_info模块

  • get_info(name,notfound_action=0)

  • combine_paths(*args,**kws)

  • show_all()

numpy.distutils.cpuinfo模块

  • cpuinfo

numpy.distutils.log模块

  • set_verbosity(v)

numpy.distutils.exec_command模块

  • get_pythonexe()

  • find_executable(exe, path=None)

  • exec_command( command, execute_in='', use_shell=None, use_tee=None, **env )

__init__.py文件

一个典型的 SciPy __init__.py的头部是:

"""
Package docstring, typically with a brief description and function listing.
"""

# import functions into module namespace
from .subpackage import *
...

__all__ = [s for s in dir() if not s.startswith('_')]

from numpy.testing import Tester
test = Tester().test
bench = Tester().bench 

NumPy Distutils 的额外功能

在 setup.py 脚本中为库指定 config_fc 选项

可以在 setup.py 脚本中指定 config_fc 选项。例如,使用

config.add_library('library',

sources=[…], config_fc={'noopt'😦file,1)})

将编译library源码时不使用优化标志。

建议仅以与编译器无关的方式指定那些 config_fc 选项

从源代码获取额外的 Fortran 77 编译器选项

一些旧的 Fortran 代码需要特殊的编译器选项才能正常工作。为了指定每个源文件的编译器选项,numpy.distutils Fortran 编译器寻找以下模式:

CF77FLAGS(<fcompiler type>) = <fcompiler f77flags> 

在源文件的前 20 行中,并使用指定类型的 fcompiler 的f77flags(第一个字符C是可选的)。

TODO:这个功能也可以轻松扩展到 Fortran 90 代码上。如果您需要这样的功能,请告诉我们。

在 setup.py 脚本中为库指定 config_fc 选项。

可以在 setup.py 脚本中指定 config_fc 选项。例如,使用

config.add_library(‘library’,

sources=[…], config_fc={‘noopt’😦file,1)})

编译library源码时不使用优化标志。

建议仅指定那些与编译器无关的 config_fc 选项。

从源码中获取额外的 Fortran 77 编译器选项。

一些旧的 Fortran 代码需要特殊的编译器选项才能正常工作。为了指定每个源文件的编译器选项,numpy.distutils Fortran 编译器寻找以下模式:

CF77FLAGS(<fcompiler type>) = <fcompiler f77flags> 

在源文件的前 20 行中,并使用指定类型的 fcompiler 的f77flags(第一个字符C是可选的)。

TODO:这个功能也可以轻松扩展到 Fortran 90 代码上。如果您需要这样的功能,请告诉我们。

numpy.distutils 的状态和迁移建议

原文:numpy.org/doc/1.26/reference/distutils_status_migration.html

numpy.distutils 已在 NumPy 1.23.0 中被弃用。它将在 Python 3.12 中被移除;对于 Python <= 3.11,它将在 Python 3.12 发布后的 2 年内不会被移除(2025 年 10 月)。

警告

numpy.distutils 仅与 setuptools < 60.0 进行了测试,更新的版本可能会出现问题。有关详细信息,请参见 numpy.distutils 与 setuptools 的交互。

迁移建议

有几个很好的选项可供迁移。假设您的软件包中有编译代码(如果没有,您有几个很好的选项,例如 Poetry、Hatch 或 PDM 提供的构建后端),并且您希望使用一个设计良好、现代且可靠的构建系统,我们建议使用:

  1. Meson,以及 meson-python 构建后端

  2. CMake,以及 scikit-build-core 构建后端

如果您的需求不高(只有简单的 Cython/C 扩展;不需要 Fortran、BLAS/LAPACK、嵌套的 setup.py 文件或 numpy.distutils 的其他功能),并且迄今为止对 numpy.distutils 感到满意,您也可以考虑切换到 setuptools。请注意,numpy.distutils 的大多数功能不太可能被移植到 setuptools

迁移到 Meson

SciPy 在其 1.9.0 版本中已经转向使用 Meson 和 meson-python。在此过程中,解决了 Meson 的 Python 支持和与 numpy.distutils 功能对齐的剩余问题。注意:对齐意味着一个大的超集(因为 Meson 是一个很好的通用构建系统);只有一些 BLAS/LAPACK 库选择的细微差别是缺失的。SciPy 几乎使用了 numpy.distutils 提供的所有功能,因此如果 SciPy 成功地使用 Meson 作为构建系统发布了一个版本,那么应该没有障碍可以阻止迁移,SciPy 将成为其他正在迁移的软件包的良好参考。有关 SciPy 迁移的更多详细信息,请参见:

NumPy 将在 1.26 版本中迁移到 Meson。

迁移到 CMake / scikit-build

下一代 scikit-build 称为 scikit-build-core。在旧的 scikit-build 使用 setuptools 作为底层时,重写不再使用。与 Meson 一样,CMake 是一个很好的通用构建系统。

迁移到 setuptools

对于仅因历史原因而使用numpy.distutils的项目,并且实际上没有使用setuptools也支持的功能,迁移到setuptools很可能是成本最低的解决方案。为评估这一点,有一些numpy.distutils功能 setuptools中存在:

  • 嵌套的setup.py文件

  • Fortran 构建支持

  • BLAS / LAPACK 库支持(OpenBLAS、MKL、ATLAS、Netlib LAPACK / BLAS、BLIS、64 位 ILP 接口等)

  • 对其他一些科学库的支持,如 FFTW 和 UMFPACK

  • 更好的 MinGW 支持

  • 每个编译器的构建标志自定义(例如* -O3 SSE2*标志是默认的)

  • 一个简单的用户构建配置系统,请查看site.cfg.example

  • SIMD 内在支持

最广泛使用的功能是嵌套的setup.py文件。该功能可能将来可能仍然被移植到setuptools中(但需要一个志愿者,见gh-18588了解状态)。只使用该功能的项目在此之后可以迁移到setuptools。如果一个项目只使用了几个setup.py文件,将这些文件的所有内容聚合到一个单独的setup.py文件中,然后迁移到setuptools可能是有意义的。这涉及放弃所有Configuration实例,并改用Extension。例如:

from distutils.core import setup
from distutils.extension import Extension
setup(name='foobar',
      version='1.0',
      ext_modules=[
          Extension('foopkg.foo', ['foo.c']),
          Extension('barpkg.bar', ['bar.c']),
          ],
      ) 

有关更多细节,请参阅setuptools 文档

numpy.distutilssetuptools的互动

建议使用setuptools < 60.0。更新的版本可能有效,但不能保证。原因是setuptools 60.0 启用了distutils的供应商副本,其中包含一些影响numpy.distutils某些功能的向后不兼容更改。

如果您只使用简单的 Cython 或 C 扩展并最小限度地使用numpy.distutils功能,超出嵌套的setup.py文件(它最流行的特性,请参阅Configuration),那么最新的setuptools可能会继续运作正常。如果出现问题,您还可以尝试SETUPTOOLS_USE_DISTUTILS=stdlib来避免setuptools中不兼容的更改。

无论您做什么,建议在pyproject.toml中对setuptools的构建需求设置一个上限,以避免未来的破坏 - 请参见对下游包作者的建议。

迁移建议

有几种可供迁移的构建系统选择。假设您的软件包中有编译代码(如果没有,您有几个良好的选择,例如 Poetry、Hatch 或 PDM 提供的构建后端),并且您希望使用一个设计良好、现代化和可靠的构建系统,我们建议:

  1. Mesonmeson-python构建后端

  2. CMakescikit-build-core构建后端

如果您只需要简单的 Cython/C 扩展(不需要 Fortran,BLAS/LAPACK,嵌套的setup.py文件或其他numpy.distutils的功能),并且迄今为止对numpy.distutils感到满意,您也可以考虑切换到setuptools。请注意,大多数numpy.distutils的功能不太可能被迁移到setuptools

迁移至 Meson

SciPy 在其 1.9.0 版本中已经迁移到了 Meson 和 meson-python。在此过程中,已解决了 Meson 的 Python 支持以及与numpy.distutils功能平等的剩余问题。注意:平等意味着一个大的超集(因为 Meson 是一个很好的通用构建系统);只有一些 BLAS/LAPACK 库选择上的小问题缺失。SciPy 几乎使用了numpy.distutils提供的所有功能,因此如果 SciPy 成功发布了使用 Meson 作为构建系统的版本,那么应该没有任何阻碍可以迁移,SciPy 将成为其他正在迁移的软件包的良好参考。有关 SciPy 迁移的更多详细信息,请参见:

NumPy 将在 1.26 版本中迁移到 Meson。

迁移到 CMake / scikit-build

下一代 scikit-build 称为scikit-build-core。旧版的scikit-build使用了setuptools作为底层,但重写并没有。与 Meson 一样,CMake 是一个很好的通用构建系统。

迁移到setuptools

对于仅出于历史原因使用numpy.distutils的项目,并且实际上没有使用setuptools也支持的功能,移至setuptools很可能是耗费最少努力的解决方案。为了评估,这里是setuptools没有存在的numpy.distutils功能:

  • 嵌套的setup.py文件

  • Fortran 构建支持

  • BLAS/LAPACK 库支持(OpenBLAS,MKL,ATLAS,Netlib LAPACK/BLAS,BLIS,64 位 ILP 接口等)

  • 支持其他几个科学库,如 FFTW 和 UMFPACK

  • 更好的 MinGW 支持

  • 每个编译器的构建标志定制(例如,默认为* -O3 SSE2 *标志)

  • 一个简单的用户构建配置系统,请参阅site.cfg.example

  • SIMD 指令集支持

最广泛使用的功能是嵌套的setup.py文件。这个功能可能将来仍然被移植到setuptools中(需要一个志愿者,参见gh-18588了解状态)。只使用该功能的项目在完成后可以转移到setuptools。如果一个项目只使用了几个setup.py文件,将这些文件的所有内容聚合到一个单独的setup.py文件中,然后转移到setuptools也是有意义的。这涉及放弃所有Configuration实例,并改用Extension。例如:

from distutils.core import setup
from distutils.extension import Extension
setup(name='foobar',
      version='1.0',
      ext_modules=[
          Extension('foopkg.foo', ['foo.c']),
          Extension('barpkg.bar', ['bar.c']),
          ],
      ) 

更多详细信息,请参见setuptools 文档

转移到 Meson。

SciPy 已经在其 1.9.0 版本中迁移到 Meson 和 meson-python。在此过程中,解决了 Meson 的 Python 支持和与numpy.distutils功能平衡的剩余问题。注意:平衡意味着一个大的超集(因为 Meson 是一个很好的通用构建系统);只有一些 BLAS/LAPACK 库选择的细微差别缺失。SciPy 几乎使用了numpy.distutils提供的所有功能,因此如果 SciPy 成功使用 Meson 作为构建系统发布了一个版本,那么应该没有障碍可以迁移,SciPy 将成为其他正在迁移的软件包的良好参考。有关 SciPy 迁移的更多详细信息,请参见:

NumPy 将在 1.26 版本中迁移到 Meson。

转移到 CMake / scikit-build。

下一代 scikit-build 被称为scikit-build-core。旧的scikit-build使用setuptools作为底层,而重写则不是。与 Meson 一样,CMake 是一个很好的通用构建系统。

转移到setuptools

对于仅出于历史原因使用numpy.distutils的项目,并且实际上没有使用setuptools支持的功能,转移到setuptools可能是付出最少努力的解决方案。为了评估这一点,有一些numpy.distutils功能存在于setuptools中:

  • 嵌套的setup.py文件。

  • Fortran 构建支持。

  • BLAS/LAPACK 库支持(OpenBLAS、MKL、ATLAS、Netlib LAPACK/BLAS、BLIS、64 位 ILP 接口等)。

  • 支持其他几个科学库,如 FFTW 和 UMFPACK。

  • 更好的 MinGW 支持。

  • 每个编译器的构建标志自定义(例如,默认为-O3SSE2标志)

  • 一个简单的用户构建配置系统,请参见site.cfg.example

  • SIMD 指令支持。

最广泛使用的功能是嵌套的setup.py文件。这个功能可能在将来仍然会被移植到setuptools中(不过需要有志愿者,参见gh-18588了解状态)。只使用该功能的项目在完成后可以转移到setuptools。如果一个项目只使用了几个setup.py文件,将这些文件的所有内容聚合到一个单独的setup.py文件中,然后转移到setuptools也是有意义的。这涉及放弃所有的Configuration实例,并使用Extension代替。例如:

from distutils.core import setup
from distutils.extension import Extension
setup(name='foobar',
      version='1.0',
      ext_modules=[
          Extension('foopkg.foo', ['foo.c']),
          Extension('barpkg.bar', ['bar.c']),
          ],
      ) 

更多详情,请参阅setuptools 文档

numpy.distutilssetuptools的交互

建议使用setuptools < 60.0。更新的版本可能会工作,但不能保证。原因是setuptools 60.0 启用了distutils的一个供应商副本,其中包含影响numpy.distutils某些功能的不兼容更改。

如果你只是简单地使用 Cython 或 C 扩展,并且最多只是在嵌套的setup.py文件之外使用了少量numpy.distutils功能(它最受欢迎的功能,请参见Configuration),那么最新的setuptools可能会继续工作。如果出现问题,你也可以尝试SETUPTOOLS_USE_DISTUTILS=stdlib来避免setuptools中的不兼容更改。

无论你做什么,建议在pyproject.toml中对你的setuptools构建需求设置一个上限,以避免未来的破坏 - 参见对下游包作者的建议。

NumPy C-API

原文:numpy.org/doc/1.26/reference/c-api/index.html

当心那些不愿意去理会细节的人。— 威廉·菲瑟(William Feather, Sr.)真相在那里。— 克里斯·卡特(Chris Carter),《X 档案》

NumPy 提供了一个 C-API,使用户能够扩展系统并访问数组对象以在其他程序中使用。真正理解 C-API 的最佳方式是阅读源代码。然而,如果你不熟悉(C)源代码,这一开始可能会让人望而生畏。请放心,随着练习,这个任务会变得更容易,你可能会惊讶于理解 C 代码的简单程度。即使你认为自己无法从头编写 C 代码,理解和修改已经编写好的源代码要比从零开始编写要容易得多。

Python 扩展特别容易理解,因为它们都具有非常相似的结构。诚然,NumPy 不是 Python 的一个琐碎扩展,可能需要更多的探索才能理解。这尤其是因为代码生成技术简化了非常相似的代码的维护,但对初学者来说可能会使代码稍微难以阅读。不过,稍加坚持,你就能理解这些代码。我希望这份关于 C-API 的指南能够帮助你熟悉使用 NumPy 进行编译级工作的过程,以便从你的代码中挤出最后一丝必要的速度。

  • Python 类型和 C 结构

    • 定义的新 Python 类型

    • 其他 C 结构

  • 系统配置

    • 数据类型大小

    • 平台信息

    • 编译器指令

  • 数据类型 API

    • 枚举类型

    • 定义

    • C 类型名称

    • Printf 格式化

  • 数组 API

    • 数组结构和数据访问

    • 创建数组

    • 处理类型

    • 数组标志

    • 数组方法替代 API

    • 函数

    • 具有对象语义的辅助数据

    • 数组迭代器

    • 广播(多迭代器)

    • 邻域迭代器

    • 数组映射

    • 数组标量

    • 数据类型描述符

    • 转换工具

    • 杂项

  • 数组迭代器 API

    • 数组迭代器

    • 迭代示例

    • 多次迭代示例

    • 多索引跟踪示例

    • 迭代器数据类型

    • 构造和销毁

    • 迭代函数

    • 从以前的 NumPy 迭代器转换

  • UFunc API

    • 常量

    • 类型

    • 函数

    • 通用函数

    • 导入 API

  • 广义通用函数 API

    • 定义

    • 签名的详细信息

    • 用于实现基本函数的 C API

  • NumPy 核心库

    • NumPy 核心数学库
  • C API 废弃

    • 背景

    • 废弃机制 NPY_NO_DEPRECATED_API

  • NumPy 中的内存管理

    • 历史概览

    • NumPy 中可配置的内存例程(NEP 49)

    • 如果没有设置策略,则释放内存时会发生什么

    • 使用 np.lib.tracemalloc_domain 进行内存跟踪的示例

Python 类型和 C 结构

原文:numpy.org/doc/1.26/reference/c-api/types-and-structures.html

几种新类型在 C 代码中定义。其中大多数可以从 Python 中访问,但由于使用受限,有些则没有暴露出来。每个新的 Python 类型都有一个关联的PyObject*,其内部结构包括指向“方法表”的指针,定义了新对象在 Python 中的行为。在 C 代码中接收到 Python 对象时,始终会得到一个指向PyObject 结构的指针。因为 PyObject 结构非常通用,仅定义了 PyObject_HEAD,因此本身并不是很有趣。但是,不同类型的对象在PyObject_HEAD之后包含更多细节(但你必须将其转换为正确的类型才能访问它们 - 或者使用访问器函数或宏)。

定义了新的 Python 类型

Python 类型在 C 语言中等效于 Python 中的类。通过构建新的 Python 类型,可以为 Python 提供一个新的对象。ndarray 对象就是在 C 中定义的一个新类型的例子。通过两个基本步骤在 C 中定义新类型:

  1. 创建一个 C 结构(通常命名为 Py{Name}Object),它与 PyObject 结构本身二进制兼容,但包含了特定对象需要的额外信息;

  2. 使用指针指向实现所需行为的函数,将PyTypeObject表(由PyObject 结构的 ob_type 成员指向)填充。

不再使用定义 Python 类的特殊方法名,而是使用指向实现所需结果的函数的“函数表”。自从 Python 2.2 开始,PyTypeObject 本身变得动态,允许从其他 C 类型“子类型化” C 类型,并在 Python 中派生子类。子类型继承其父类的属性和方法。

有两种主要的新类型:ndarray( PyArray_Type )和 ufunc( PyUFunc_Type )。其他类型起着支持作用:PyArrayIter_TypePyArrayMultiIter_TypePyArrayDescr_TypePyArrayIter_Type 是用于 ndarray 的平面迭代器的类型(获取 flat 属性时返回的对象)。PyArrayMultiIter_Type 是在调用 broadcast () 时返回的对象的类型。它处理对嵌套序列集合的迭代和广播。此外,PyArrayDescr_Type 是描述数据的数据类型描述符类型,其实例描述数据。最后,有 21 种新的标量数组类型,它们是与数组可用的每种基本数据类型对应的新的 Python 标量。另外还有 10 种其他类型是占位符,允许数组标量适应实际 Python 类型的层次结构。

PyArray_Type 和 PyArrayObject

PyArray_Type

ndarray 的 Python 类型是 PyArray_Type。在 C 中,每个 ndarray 都是指向 PyArrayObject 结构的指针。此结构的 ob_type 成员包含指向 PyArray_Type 类型对象的指针。

type PyArrayObject
type NPY_AO

PyArrayObject C 结构包含数组的所有必需信息。所有 ndarray(及其子类)的实例都将具有此结构。为了未来的兼容性,应该通常使用提供的宏来访问这些结构成员。如果需要更短的名称,那么可以使用已弃用的 NPY_AO,它被定义为等同于 PyArrayObject。直接访问结构字段已被弃用。请改用 PyArray_*(arr) 形式。截至 NumPy 1.20,此结构的大小不被视为 NumPy ABI 的一部分(请参见成员列表末尾的注释)。

typedef  struct  PyArrayObject  {
  PyObject_HEAD
  char  *data;
  int  nd;
  npy_intp  *dimensions;
  npy_intp  *strides;
  PyObject  *base;
  PyArray_Descr  *descr;
  int  flags;
  PyObject  *weakreflist;
  /* version dependent private members */
}  PyArrayObject; 
PyObject_HEAD

这是所有 Python 对象所需的。它至少包含一个引用计数成员( ob_refcnt )和一个指向类型对象的指针( ob_type )。(如果 Python 是使用特殊选项编译的,还可能存在其他元素,请参阅 Python 源树中的 Include/object.h 了解更多信息)。ob_type 成员指向 Python 类型对象。

char *data

通过 PyArray_DATA 可访问,此数据成员是数组的第一个元素的指针。这个指针可以(通常应该)重新转换为数组的数据类型。

int nd

一个整数,提供此数组的维数。当 nd 为 0 时,有时称为秩-0 数组。这种数组具有未定义的维度和步幅,无法访问。宏PyArray_NDIM定义在ndarraytypes.h指向这个数据成员。NPY_MAXDIMS 是任何数组的最大维数。

*dimensions

一个整数数组,为每个维度提供该维度中的形状,只要 nd (\geq) 1。这个整数总是足够大,能够在平台上保存一个指针,所以维度大小仅受内存限制。PyArray_DIMS 是与这个数据成员相关联的宏。

*strides

一个整数数组,为每个维度提供必须跳过的字节数,以到达该维度中的下一个元素。与宏PyArray_STRIDES相关联。

*base

PyArray_BASE指向,这个成员用于保存与这个数组相关的另一个 Python 对象的指针。有两个用例:

  • 如果这个数组没有拥有自己的内存,那么 base 指向拥有它的 Python 对象(也许是另一个数组对象)。

  • 如果这个数组设置了NPY_ARRAY_WRITEBACKIFCOPY标志,那么这个数组是一个“不良”数组的工作副本。

当调用PyArray_ResolveWritebackIfCopy时,base 指向的数组将使用这个数组的内容更新。

*descr

指向数据类型描述符对象的指针(见下文)。数据类型描述符对象是新建的内置类型的实例,它允许对内存进行通用描述。对每个支持的数据类型都存在一个描述符结构。这个描述符结构包含有关类型的有用信息,以及一个指向实现特定功能的函数指针表的指针。顾名思义,它与宏PyArray_DESCR相关联。

int flags

由宏PyArray_FLAGS指向,这个数据成员表示标志,指示数据指针指向的内存应如何解释。可能的标志是NPY_ARRAY_C_CONTIGUOUSNPY_ARRAY_F_CONTIGUOUSNPY_ARRAY_OWNDATANPY_ARRAY_ALIGNEDNPY_ARRAY_WRITEABLENPY_ARRAY_WRITEBACKIFCOPY

*weakreflist

这个成员允许数组对象具有弱引用(使用 weakref 模块)。

注意

其他成员被视为私有和与版本有关。如果结构的大小对您的代码很重要,必须特别小心。当这一点相关时的一种可能的用例是在 C 中进行子类化。如果您的代码依赖于 sizeof(PyArrayObject) 的大小是不变的,您在导入时必须添加以下检查:

if  (sizeof(PyArrayObject)  <  PyArray_Type.tp_basicsize)  {
  PyErr_SetString(PyExc_ImportError,
  "Binary incompatibility with NumPy, must recompile/update X.");
  return  NULL;
} 

为了确保您的代码不必为特定的 NumPy 版本进行编译,您可以添加一个常数,留出 NumPy 变化的空间。可确保与将来任何 NumPy 版本兼容的解决方案需要使用运行时计算偏移和分配大小。

PyArrayDescr_Type 和 PyArray_Descr

PyArrayDescr_Type

PyArrayDescr_Type 是用于描述数组所包含的字节应如何解释的数据类型描述对象的内置类型。内置数据类型有 21 个静态定义的 PyArray_Descr 对象。虽然这些对象参与引用计数,但它们的引用计数永远不应该达到零。还有一个动态的用户自定义 PyArray_Descr 对象表也会被维护。一旦数据类型描述对象被“注册”,它就不应该被释放。函数 PyArray_DescrFromType (…) 可以用来从一个枚举类型编号(内置或用户自定义)中检索出一个 PyArray_Descr 对象。

type PyArray_Descr

PyArray_Descr 结构位于 PyArrayDescr_Type 的核心。虽然这里描述了它,但它应被视为 NumPy 的内部部分,并通过 PyArrayDescr_*PyDataType* 函数和宏进行操作。这个结构的大小会随着 NumPy 的版本变化而变化。为确保兼容性:

  • 永远不要声明结构的非指针实例

  • 永远不要执行指针算术运算

  • 永远不要使用 sizeof(PyArray_Descr)

它具有以下结构:

typedef  struct  {
  PyObject_HEAD
  PyTypeObject  *typeobj;
  char  kind;
  char  type;
  char  byteorder;
  char  flags;
  int  type_num;
  int  elsize;
  int  alignment;
  PyArray_ArrayDescr  *subarray;
  PyObject  *fields;
  PyObject  *names;
  PyArray_ArrFuncs  *f;
  PyObject  *metadata;
  NpyAuxData  *c_metadata;
  npy_hash_t  hash;
}  PyArray_Descr; 
*typeobj

指向该数组元素对应的 Python 类型的类型对象的指针。对于内置类型,这将指向对应的 array scalar。对于用户定义类型,这应该指向用户定义的类型对象。这个类型对象可以继承自数组标量,也可以不继承。如果它不继承自数组标量,那么flags 成员中应该设置 NPY_USE_GETITEMNPY_USE_SETITEM 标志。

char kind

表示数组种类的字符代码(使用数组接口类型字符串表示)。‘b’ 表示布尔型,‘i’ 表示有符号整数,‘u’ 表示无符号整数,‘f’ 表示浮点型,‘c’ 表示复数浮点型,‘S’ 表示 8 位零终结字节,‘U’ 表示 32 位/字符 Unicode 字符串,‘V’ 表示任意类型。

char type

指示数据类型的传统字符代码。

char byteorder

表示字节顺序的字符:‘>’(大端),‘<’(小端),‘=’(本地),‘|’(不相关,忽略)。所有内置数据类型的字节顺序为‘=’。

char flags

决定数据类型是否具有对象数组行为的数据类型位标志。此成员中的每个位都是一个标志,其命名为:

  • NPY_ITEM_REFCOUNT

  • NPY_ITEM_HASOBJECT

  • NPY_LIST_PICKLE

  • NPY_ITEM_IS_POINTER

  • NPY_NEEDS_INIT

  • NPY_NEEDS_PYAPI

  • NPY_USE_GETITEM

  • NPY_USE_SETITEM

  • NPY_FROM_FIELDS

  • NPY_OBJECT_DTYPE_FLAGS

int type_num

唯一标识数据类型的数字。对于新的数据类型,当数据类型注册时会分配此数字。

int elsize

对于始终大小相同的数据类型(例如 long),这表示数据类型的大小。对于灵活的数据类型,其中不同的数组可以具有不同的元素大小,这应为 0。

int alignment

提供此数据类型的对齐信息的数字。具体来说,它显示编译器在从 2 个元素结构的开始(其第一个元素是一个 char)放置此类型的项目的距离:offsetof(struct {char c; type v;}, v)

*subarray

如果此为非 NULL,则此数据类型描述符是另一个数据类型描述符的 C 风格连续数组。换句话说,此描述符描述的每个元素实际上是另一个基本描述符的数组。如果此为非 NULL,则字段成员应为 NULL(但是基本描述符的字段成员可以为非 NULL)。

type PyArray_ArrayDescr
typedef  struct  {
  PyArray_Descr  *base;
  PyObject  *shape;
}  PyArray_ArrayDescr; 
*base

基本类型的数据类型描述符对象。

*shape

子数组的形状(始终为 C 风格连续)作为 Python 元组。

*fields

如果此为非空,则此数据类型描述符具有由 Python 字典描述的字段,其键是名称(如果给定也是标题),其值是描述字段的元组。请注意,数据类型描述符始终描述一组固定长度的字节。字段是总的、固定长度集合的命名子区域。字段由另一个数据类型描述符和字节偏移量组成的元组描述。可选地,元组可能包含通常为 Python 字符串的标题。这些元组根据名称(如果给定还有标题)放置在此字典中。

*names

字段名称的有序元组。如果未定义字段,则为 NULL。

*f

指向一个包含类型需要实现内部特性的函数的结构体的指针。这些函数不同于后面描述的通用函数(ufuncs)。它们的签名可以任意变化。

*metadata

关于此数据类型的元数据。

*c_metadata

这些特定于特定 dtype 的 C 实现的元数据。增加于 NumPy 1.7.0。

type npy_hash_t
*hash

目前未使用。保留以用于在缓存哈希值中将来使用。

NPY_ITEM_REFCOUNT

表示此数据类型的项必须进行引用计数(使用Py_INCREFPy_DECREF)。

NPY_ITEM_HASOBJECT

等同于NPY_ITEM_REFCOUNT

NPY_LIST_PICKLE

表示必须将这种数据类型的数组在 pickling 之前转换为列表。

NPY_ITEM_IS_POINTER

表示该项是指向其他数据类型的指针。

NPY_NEEDS_INIT

表示必须在创建时初始化(设置为 0)此数据类型的内存。

NPY_NEEDS_PYAPI

表示在访问时此数据类型需要 Python C-API(因此如果需要数组访问,请不要放弃 GIL)。

NPY_USE_GETITEM

在数组访问时,使用f->getitem函数指针,而不是标准的转换为数组标量。如果没有定义与数据类型相匹配的数组标量,必须使用。

NPY_USE_SETITEM

当从数组标量创建 0 维数组时,使用f->setitem而不是标准的从数组标量复制。如果你没有定义与数据类型相匹配的数组标量,必须使用。

NPY_FROM_FIELDS

如果在数据类型的任何字段中设置了这些位,则从父数据类型继承这些位。目前(NPY_NEEDS_INIT | NPY_LIST_PICKLE | NPY_ITEM_REFCOUNT | NPY_NEEDS_PYAPI)。

NPY_OBJECT_DTYPE_FLAGS

为对象数据类型设置的位:(NPY_LIST_PICKLE | NPY_USE_GETITEM | NPY_ITEM_IS_POINTER | NPY_ITEM_REFCOUNT | NPY_NEEDS_INIT | NPY_NEEDS_PYAPI)。

int PyDataType_FLAGCHK( *dtype, int flags)

如果数据类型对象的所有给定标志都设置为真,则返回真。

int PyDataType_REFCHK( *dtype)

等同于PyDataType_FLAGCHKdtypeNPY_ITEM_REFCOUNT)。

type PyArray_ArrFuncs

实现内部特性的函数。并非必须为给定类型定义所有这些函数指针。必须定义的成员包括nonzerocopyswapcopyswapnsetitemgetitemcast。这默认假定为非 NULL,而NULL条目将导致程序崩溃。其他函数可以是 NULL,这只会导致该数据类型的功能减少。(此外,如果在注册用户定义的数据类型时nonzero函数为空,将使用默认函数填充nonzero函数)。

typedef  struct  {
  PyArray_VectorUnaryFunc  *cast[NPY_NTYPES];
  PyArray_GetItemFunc  *getitem;
  PyArray_SetItemFunc  *setitem;
  PyArray_CopySwapNFunc  *copyswapn;
  PyArray_CopySwapFunc  *copyswap;
  PyArray_CompareFunc  *compare;
  PyArray_ArgFunc  *argmax;
  PyArray_DotFunc  *dotfunc;
  PyArray_ScanFunc  *scanfunc;
  PyArray_FromStrFunc  *fromstr;
  PyArray_NonzeroFunc  *nonzero;
  PyArray_FillFunc  *fill;
  PyArray_FillWithScalarFunc  *fillwithscalar;
  PyArray_SortFunc  *sort[NPY_NSORTS];
  PyArray_ArgSortFunc  *argsort[NPY_NSORTS];
  PyObject  *castdict;
  PyArray_ScalarKindFunc  *scalarkind;
  int  **cancastscalarkindto;
  int  *cancastto;
  PyArray_FastClipFunc  *fastclip;  /* deprecated */
  PyArray_FastPutmaskFunc  *fastputmask;  /* deprecated */
  PyArray_FastTakeFunc  *fasttake;  /* deprecated */
  PyArray_ArgFunc  *argmin;
}  PyArray_ArrFuncs; 

描述函数指针时使用了行为良好段的概念。行为良好的段是指与数据类型对齐且符合本机字节顺序的段。nonzerocopyswapcopyswapngetitemsetitem 函数可以(必须)处理不规范的数组。其他函数则需要行为良好的内存段。

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

一个函数指针数组,用于将当前类型转换为所有其他内置类型。每个函数都将由 from 指向的连续、对齐且未交换的缓冲区转换为由 to 指向的连续、对齐且未交换的缓冲区。要转换的项数由 n 给出,并且参数 fromarrtoarr 被解释为灵活数组的 PyArrayObjects 以获取 itemsize 信息。

*getitem(void *data, void *arr)

一个函数指针,用于从由 data 指向的数组对象 arr 的单个元素返回标准 Python 对象。此函数必须能够正确处理“不规范”的(未对齐和/或交换的)数组。

int setitem( *item, void *data, void *arr)

一个函数指针,用于将 Python 对象 item 设置到由 data 指向的数组 arr 中的位置。此函数处理“不规范”的数组。如果成功,返回零,否则返回负一(并设置 Python 错误)。

void copyswapn(void *dest, dstride, void *src, sstride, n, int swap, void *arr)
void copyswap(void *dest, void *src, int swap, void *arr)

这些成员都是指向从 src 复制数据到 dest 并在需要时交换的函数的指针。仅当为灵活数组(NPY_STRINGNPY_UNICODENPY_VOID )时才使用 arr 的值(从 arr->descr->elsize 获取)。第二个函数复制单个值,而第一个函数则使用提供的步幅循环 n 值。这些函数可以处理不规范的 src 数据。如果 src 为 NULL,则不执行复制。如果 swap 为 0,则不执行字节交换。假设 destsrc 不重叠。如果它们重叠,则首先使用 memmove(…)再使用值为 NULL 的 src 执行 copyswap(n)

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

一个函数指针,用于比较由 d1d2 指向的数组 arr 的两个元素。此函数需要行为良好(对齐且未交换)的数组。如果 * d1 > * d2,返回值为 1;如果 * d1 == * d2,返回值为 0;如果 * d1 < * d2,返回值为 -1。数组对象 arr 用于检索灵活数组的 itemsize 和字段信息。

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

一个函数指针,用于从由 data 指向的元素开始的 n 个元素中检索最大的索引。此函数要求内存段是连续且行为良好的。返回值始终为 0。最大元素的索引在 max_ind 中返回。

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

一个指向将两个n长度的序列相乘,相加,并将结果放置到由op指向的arr元素中的函数的指针。序列的开始分别由ip1ip2指向。要获取每个序列中的下一个元素需要跳过is1is2 字节。此函数需要表现良好的(尽管不一定是连续的)内存。

int scanfunc(FILE *fd, void *ip, void *arr)

一个指向从文件描述符fd中扫描(类似于 scanf)相应类型的元素到由ip指向的数组内存中的函数的指针。假定数组表现良好。最后一个参数arr是要扫描的数组。返回成功分配的接收参数的数量(如果在分配第一个接收参数之前匹配失败,则可能为零),或者如果在分配第一个接收参数之前发生输入故障,则为 EOF。调用此函数时应该不持有 Python GIL,并且必须为错误报告抓取它。

int fromstr(char *str, void *ip, char **endptr, void *arr)

一个指向将str指向的字符串转换为相应类型的一个元素并将其放置到由ip指向的内存位置的函数的指针。转换完成后,*endptr指向字符串的其余部分。最后一个参数arr是 ip 指向的数组(需要用于变量大小数据类型)。成功返回 0,失败返回-1。需要一个表现良好的数组。调用此函数时应该不持有 Python GIL,并且必须为错误报告抓取它。

nonzero(void *data, void *arr)

一个指向如果data指向的arr的项为非零则返回 TRUE 的函数的指针。此函数可以处理行为不当的数组。

void fill(void *data, length, void *arr)

一个指向填充给定长度的连续数组数据的函数的指针。数组的前两个元素必须已经被填充。根据这两个值,将计算出一个增量,然后从第 3 个元素到最后的值将通过重复添加这个计算出的增量来计算。数据缓冲区必须表现良好。

void fillwithscalar(void *buffer, length, void *value, void *arr)

一个指向使用单个标量value的地址填充给定长度的连续buffer的函数的指针。最后一个参数是所需用于变长数组的 itemsize 的数组。

int sort(void *start, length, void *arr)

一个指向特定排序算法的函数指针数组。可以使用一个关键字(到目前为止定义了NPY_QUICKSORTNPY_HEAPSORTNPY_MERGESORT)。这些排序是在假定连续和对齐的数据上进行的。

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

一个指向此数据类型的排序算法的函数指针数组。可用于排序的排序算法与 sort 相同。产生排序的索引被返回到result中(必须初始化为包含 0 到length-1的索引)。

*castdict

可以是NULL或包含用户定义数据类型的低级转换函数的字典。每个函数都包装在一个PyCapsule*中,并以数据类型编号为键。

scalarkind( *arr)

用于确定此类型的标量应如何解释的函数。参数是一个包含数据的 0 维数组(如果需要确定标量的种类,则需要该数据)。返回值必须是类型为NPY_SCALARKIND的值。

int **cancastscalarkindto

可以是NULL或一个包含NPY_NSCALARKINDS指针的数组。这些指针每个都应该是NULL,或者是指向整数数组的指针(以NPY_NOTYPE终止),指示此数据类型的指定种类的标量可以安全地转换为的数据类型(通常意味着不会失去精度)。

int *cancastto

可以是NULL或一个整数数组(以NPY_NOTYPE终止),指示此数据类型可以安全地转换为的数据类型(通常意味着不会失去精度)。

void fastclip(void *in, n_in, void *min, void *max, void *out)

自版本 1.17 起弃用:使用此函数将在np.clip时产生弃用警告。不再使用此函数,数据类型必须使用PyUFunc_RegisterLoopForDescr将自定义循环附加到np.core.umath.clipnp.minimumnp.maximum

自版本 1.19 起弃用:设置此函数已被弃用,应始终为NULL,如果设置,将被忽略。

in中读取n_in项,并在其指向的限制范围内写入到out,如果超出范围,则写入相应的限制值。内存段必须是连续的且行为良好,minmax中的一个可以是NULL,但不能同时为空。

void fastputmask(void *in, void *mask, n_in, void *values, nv)

自版本 1.19 起弃用:设置此函数已被弃用,应始终为NULL,如果设置,将被忽略。

一个函数,它接受一个指向长度为n_in项的数组的指针in,一个指向长度为n_in的布尔值数组的指针mask,以及一个指向长度为nv项的数组的指针vals。将vals中的项复制到in中,其中mask中的值为非零,如果nv < n_in,则根据需要平铺vals。所有数组必须是连续的且行为良好。

void fasttake(void *dest, void *src, *indarray, nindarray, n_outer, m_middle, nelem, clipmode)

自版本 1.19 起弃用:设置此函数已被弃用,应始终为NULL,如果设置,将被忽略。

一个函数,它接受一个指针src,指向一个 C 连续的、行为良好的段,解释为形状为(n_outer, nindarray, nelem)的三维数组,一个指向m_middle整数索引的 C 连续的、行为良好的段的指针indarray,以及一个指向 C 连续的、行为良好的段的指针dest,解释为形状为(n_outer, m_middle, nelem)的三维数组。indarray 中的索引用于沿第二维索引src,并将对应的nelem项的块复制到dest中。clipmode(可以取值NPY_RAISENPY_WRAPNPY_CLIP)确定如何处理小于 0 或大于nindarray的索引。

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

一个函数指针,用于检索从data指向的元素开始的包含n个元素的arr中最小元素的索引。此函数要求内存段是连续的且行为良好。返回值始终为 0。最小元素的索引将返回到min_ind中。

PyArray_Type 类型对象实现了许多Python 对象的特性,包括tp_as_numbertp_as_sequencetp_as_mappingtp_as_buffer 接口。富比较 也与新式属性查找一起使用,用于成员(tp_members)和属性(tp_getset)的访问。PyArray_Type 也可以被子类型化。

提示

tp_as_number 方法使用一种通用方法调用已注册用于处理操作的任何函数。当导入_multiarray_umath 模块时,它将所有数组的数值操作设置为相应的 ufuncs。可以使用PyUFunc_ReplaceLoopBySignature 来更改此选择。tp_strtp_repr 方法也可以使用PyArray_SetStringFunction 进行更改。

PyUFunc_Type 和 PyUFuncObject

PyUFunc_Type

ufunc 对象是通过创建PyUFunc_Type来实现的。 它是一种非常简单的类型,只实现了基本的 getAttribute 行为、打印行为,并且有 call 行为,这样这些对象就可以像函数一样。 ufunc 的基本思想是保存对支持操作的数据类型的快速 1 维(向量)循环的引用。 所有这些一维循环都具有相同的签名,并且是创建新 ufunc 的关键。 它们由通用循环代码适当调用以实现 N 维函数。 还为浮点和复数浮点数组定义了一些通用的一维循环,允许你使用单个标量函数(例如atanh)来定义 ufunc。

type PyUFuncObject

ufunc 的核心是PyUFuncObject,其中包含调用执行实际工作的基础 C 代码循环所需的所有信息。 虽然这里描述了这一点以确保兼容性: infotext default可以在不同的 NumPy 版本中更改。 为了确保兼容性。

  • 绝不声明结构的非指针实例

  • 永远不要执行指针算术

  • 永远不要使用sizeof(PyUFuncObject)

它具有以下结构:

typedef  struct  {
  PyObject_HEAD
  int  nin;
  int  nout;
  int  nargs;
  int  identity;
  PyUFuncGenericFunction  *functions;
  void  **data;
  int  ntypes;
  int  reserved1;
  const  char  *name;
  char  *types;
  const  char  *doc;
  void  *ptr;
  PyObject  *obj;
  PyObject  *userloops;
  int  core_enabled;
  int  core_num_dim_ix;
  int  *core_num_dims;
  int  *core_dim_ixs;
  int  *core_offsets;
  char  *core_signature;
  PyUFunc_TypeResolutionFunc  *type_resolver;
  PyUFunc_LegacyInnerLoopSelectionFunc  *legacy_inner_loop_selector;
  void  *reserved2;
  npy_uint32  *op_flags;
  npy_uint32  *iter_flags;
  /* new in API version 0x0000000D */
  npy_intp  *core_dim_sizes;
  npy_uint32  *core_dim_flags;
  PyObject  *identity_value;
  /* Further private slots (size depends on the NumPy version) */
}  PyUFuncObject; 
int nin

输入参数的数量。

int nout

输出参数的数量。

int nargs

参数的总数(* nin * + * nout *)。 这必须小于NPY_MAXARGS

int identity

PyUFunc_OnePyUFunc_ZeroPyUFunc_MinusOnePyUFunc_NonePyUFunc_ReorderableNonePyUFunc_IdentityValue中的任何一个,以指示此操作的标识。 仅用于对空数组进行类似缩小的调用。

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

一个函数指针数组 - 每种 ufunc 支持的数据类型一个。 这是被调用以实现基础功能dims[0]次的向量循环。 第一个参数args是一个* nargs 指针的数组,指向行为良好的内存。 首先是输入参数数据的指针,然后是输出参数数据的指针。 必须跳过多少字节才能到达序列中下一个元素由 steps 数组中的对应条目指定。 最后一个参数允许循环接收额外信息。 通常用于使单个通用向量循环用于多个函数。 在这种情况下,要调用的实际标量函数被传递为 extradata *。 这个函数指针数组的大小是 ntypes。

void **data

要传递给 1-d 向量循环的额外数据,如果不需要额外数据则为NULL。这个 C 数组必须与函数数组的大小相同( ntypes)。如果不需要额外数据,则使用NULL。几个用于 UFuncs 的 C API 调用只是利用这些额外数据运行 1-d 向量循环,以接收指向要调用的实际函数的指针。

int ntypes

ufunc 支持的数据类型数。这个数字指定可用的不同 1-d 循环(内置数据类型)的数量。

int reserved1

未使用。

char *name

为 ufunc 的字符串名称。这是动态使用的,用于构建 ufunc 的 doc 属性。

char *types

一个 (nargs \times ntypes) 8 位类型编号数组,包含每个支持(内置)数据类型的函数的类型签名。对于每个 ntypes 函数,该数组中对应的一组类型编号显示了如何在 1-d 向量循环中解释 args 参数。这些类型编号不必是相同类型,支持混合类型的 ufunc。

char *doc

用于 ufunc 的文档。不应包含函数签名,因为在检索 doc 时动态生成。

void *ptr

任何动态分配的内存。目前,这用于从 Python 函数创建动态 ufunc,用于存储类型、数据和名称成员的空间。

*obj

对于从 Python 函数动态创建的 ufunc,该成员持有对底层 Python 函数的引用。

*userloops

用户定义的 1-d 向量循环的字典(存储为 CObject 指针)用于用户定义的类型。用户可以为任何用户定义的类型注册循环。它通过类型编号检索。用户定义的类型编号总是大于NPY_USERDEF

int core_enabled

标量 ufunc 为 0;广义 ufunc 为 1

int core_num_dim_ix

签名中具有不同核心维度名称的数量

int *core_num_dims

每个参数的核心维度数

int *core_dim_ixs

展平形式的维度索引;参数k的索引存储在core_dim_ixs[core_offsets[k] : core_offsets[k] + core_numdims[k]]

int *core_offsets

每个参数在core_dim_ixs中第 1 个核心维度的位置,相当于 cumsum(core_num_dims)

char *core_signature

核心签名字符串

PyUFunc_TypeResolutionFunc *type_resolver

解析类型并填充输入和输出的 dtypes 的函数

PyUFunc_LegacyInnerLoopSelectionFunc *legacy_inner_loop_selector

从版本 1.22 起弃用:此插槽存在一些回退支持,但最终将被移除。依赖于此的通用函数最终将需要移植。请参阅NEP 41NEP 43

void *reserved2

用于可能的具有不同签名的未来循环选择器。

op_flags

为每个 ufunc 操作数覆盖默认操作数标志。

iter_flags

为 ufunc 覆盖默认 nditer 标志。

添加在 API 版本 0x0000000D 中

*core_dim_sizes

对于每个不同的核心维度,如果 UFUNC_CORE_DIM_SIZE_INFERRED0,则可能的 frozen 大小

*core_dim_flags

对于每个不同的核心维度,一组标志(UFUNC_CORE_DIM_CAN_IGNOREUFUNC_CORE_DIM_SIZE_INFERRED

*identity_value

缩减的标识,当 PyUFuncObject.identity 等于 PyUFunc_IdentityValue 时。

UFUNC_CORE_DIM_CAN_IGNORE

如果维度名称以 ? 结尾

UFUNC_CORE_DIM_SIZE_INFERRED

如果维度大小将由操作数而不是从 frozen 签名确定

PyArrayIter_Type 和 PyArrayIterObject

PyArrayIter_Type

这是一个迭代器对象,使得可以轻松地循环遍历 N 维数组。它是从 ndarray 的 flat 属性返回的对象。它还在整个实现内部广泛使用,以循环遍历 N 维数组。实现了 tp_as_mapping 接口,以便可以索引迭代器对象(使用 1-d 索引),并且通过 tp_methods 表实现了一些方法。此对象实现了 next 方法,并且可以在 Python 中使用任何迭代器可以使用的地方。

type PyArrayIterObject

PyArrayIter_Type 对象对应的 C 结构是 PyArrayIterObjectPyArrayIterObject 用于跟踪指向 N 维数组的指针。它包含用于快速遍历数组的相关信息。指针可以通过三种基本方式进行调整:1)以 C 风格连续地前进到数组中的“下一个”位置,2)前进到数组中的任意 N 维坐标,和 3)前进到数组中的任意一维索引。PyArrayIterObject 结构的成员在这些计算中使用。迭代器对象保存关于数组的自己的维度和跨度信息。这可以根据需要进行“广播”,或者仅循环特定维度。

typedef  struct  {
  PyObject_HEAD
  int  nd_m1;
  npy_intp  index;
  npy_intp  size;
  npy_intp  coordinates[NPY_MAXDIMS];
  npy_intp  dims_m1[NPY_MAXDIMS];
  npy_intp  strides[NPY_MAXDIMS];
  npy_intp  backstrides[NPY_MAXDIMS];
  npy_intp  factors[NPY_MAXDIMS];
  PyArrayObject  *ao;
  char  *dataptr;
  npy_bool  contiguous;
}  PyArrayIterObject; 
int nd_m1

(N-1) 其中 (N) 是底层数组中的维数。

index

数组中的当前 1-d 索引。

size

底层数组的总大小。

*coordinates

对数组的 (N) 维索引。

*dims_m1

数组在每个维度上的大小减去 1。

*strides

数组的跨度。在每个维度跳转到下一个元素所需的字节数。

*backstrides

从维度的末尾跳回到其开头所需的字节数。请注意 backstrides[k] == strides[k] * dims_m1[k],但这里存储为一种优化。

*factors

此数组用于从 1-d 索引计算 N-d 索引。它包含维度的所需乘积。

*ao

指向创建此迭代器代表的底层 ndarray 的指针。

char *dataptr

此成员指向由索引指示的 ndarray 中的元素。

contiguous

若底层数组是 NPY_ARRAY_C_CONTIGUOUS,则此标志为真。在可能的情况下,可用于简化计算。

如何在 C 级别上使用数组迭代器在后续章节中有更详细的解释。通常,您无需关心迭代器对象的内部结构,只需通过宏 PyArray_ITER_NEXT (it)、PyArray_ITER_GOTO (it, dest) 或 PyArray_ITER_GOTO1D (it, index) 与其进行交互。所有这些宏都需要参数 it 为 PyArrayIterObject*。

PyArrayMultiIter_Type 和 PyArrayMultiIterObject

PyArrayMultiIter_Type

该类型提供了一种封装广播概念的迭代器。它允许 (N) 个数组一起进行广播,使循环以 C 样式连续方式在广播的数组上进行。相应的 C 结构是 PyArrayMultiIterObject,其内存布局必须以传递给 PyArray_Broadcast (obj) 函数的任何对象 obj 开始。通过调整数组迭代器来执行广播,使得每个迭代器表示广播的形状和大小,但其步长被调整,以便在每次迭代中使用数组的正确元素。

type PyArrayMultiIterObject
typedef  struct  {
  PyObject_HEAD
  int  numiter;
  npy_intp  size;
  npy_intp  index;
  int  nd;
  npy_intp  dimensions[NPY_MAXDIMS];
  PyArrayIterObject  *iters[NPY_MAXDIMS];
}  PyArrayMultiIterObject; 
int numiter

需要广播到相同形状的数组的数量。

size

总的广播大小。

index

当前(1-d)索引进入广播结果。

int nd

广播结果中的维数。

*dimensions

广播结果的形状(仅使用 nd 槽)。

**iters

一个迭代器对象数组,其中包含要一起广播的数组的迭代器。返回时,迭代器会进行调整以进行广播。

PyArrayNeighborhoodIter_Type 和 PyArrayNeighborhoodIterObject

PyArrayNeighborhoodIter_Type

这是一个迭代器对象,可轻松循环遍历 N 维邻域。

type PyArrayNeighborhoodIterObject

PyArrayNeighborhoodIter_Type 对象对应的 C 结构是 PyArrayNeighborhoodIterObject

typedef  struct  {
  PyObject_HEAD
  int  nd_m1;
  npy_intp  index,  size;
  npy_intp  coordinates[NPY_MAXDIMS]
  npy_intp  dims_m1[NPY_MAXDIMS];
  npy_intp  strides[NPY_MAXDIMS];
  npy_intp  backstrides[NPY_MAXDIMS];
  npy_intp  factors[NPY_MAXDIMS];
  PyArrayObject  *ao;
  char  *dataptr;
  npy_bool  contiguous;
  npy_intp  bounds[NPY_MAXDIMS][2];
  npy_intp  limits[NPY_MAXDIMS][2];
  npy_intp  limits_sizes[NPY_MAXDIMS];
  npy_iter_get_dataptr_t  translate;
  npy_intp  nd;
  npy_intp  dimensions[NPY_MAXDIMS];
  PyArrayIterObject*  _internal_iter;
  char*  constant;
  int  mode;
}  PyArrayNeighborhoodIterObject; 

PyArrayFlags_Type 和 PyArrayFlagsObject

PyArrayFlags_Type

当从 Python 中检索 flags 属性时,将构建此特殊内置对象的特殊类型。这种特殊类型通过将它们作为属性访问或通过将对象视为具有标志名称条目的字典来访问它们,使得更容易处理不同的标志。

type PyArrayFlagsObject
typedef  struct  PyArrayFlagsObject  {
  PyObject_HEAD
  PyObject  *arr;
  int  flags;
}  PyArrayFlagsObject; 

ScalarArrayTypes

每种内置数据类型在 Python 中都有一个类型。这些大多是简单的包装器,用于对应 C 中的相应数据类型。这些类型的 C 名称为Py{TYPE}ArrType_Type,其中{TYPE}可以是

BoolByteShortIntLongLongLongUByteUShortUIntULongULongLongHalfFloatDoubleLongDoubleCFloatCDoubleCLongDoubleStringUnicodeVoidObject

这些类型名称是 C-API 的一部分,因此可以在扩展的 C 代码中创建。还有一个PyIntpArrType_Type和一个PyUIntpArrType_Type,它们是平台上可以容纳指针的整数类型之一的简单替代品。这些标量对象的结构对 C 代码不可见。函数PyArray_ScalarAsCtype(..)可以用于从数组标量中提取 C 类型值,函数PyArray_Scalar(…)可以用于从 C 值构造数组标量。

其他 C-结构

开发 NumPy 时发现有几个新的 C-结构很有用。这些 C 结构至少在一个 C-API 调用中使用,因此在这里记录。定义这些结构的主要原因是为了方便使用 Python ParseTuple C-API,将 Python 对象转换为有用的 C 对象。

PyArray_Dims

type PyArray_Dims

当形状和/或步幅信息被解释时,这个结构非常有用。结构如下:

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

这个结构体的成员是

*ptr

一个指向(npy_intp)整数列表的指针,通常表示数组形状或数组步幅。

int len

整数列表的长度。假定安全访问ptr[0]至ptr[len-1]。

PyArray_Chunk

type PyArray_Chunk

这与 Python 中的缓冲对象结构相当,直到 ptr 成员。在 32 位平台上(如果NPY_SIZEOF_INT == NPY_SIZEOF_INTP),len 成员也与缓冲对象的等效成员匹配。它用于表示通用的单段内存块。

typedef  struct  {
  PyObject_HEAD
  PyObject  *base;
  void  *ptr;
  npy_intp  len;
  int  flags;
}  PyArray_Chunk; 

成员是

*base

此内存块来自的 Python 对象。需要这样才能正确地计算内存。

void *ptr

单段内存块开始的指针。

len

段的长度(以字节为单位)。

int flags

用来解释内存的任何数据标志(例如 NPY_ARRAY_WRITEABLE)。

PyArrayInterface

另请参阅

数组接口协议

type PyArrayInterface

PyArrayInterface 结构被定义为 NumPy 和其他扩展模块可以使用快速的数组接口协议。支持快速数组接口协议的对象的__array_struct__方法应该返回一个包含指向PyArrayInterface结构的相关细节的指针的PyCapsule。创建新数组后,应该对属性执行DECREF,这将释放PyArrayInterface结构。记得对检索到的__array_struct__属性的对象进行INCREF,并将新的PyArrayObject的 base 成员指向这个相同的对象。以这种方式管理数组的内存将是正确的。

typedef  struct  {
  int  two;
  int  nd;
  char  typekind;
  int  itemsize;
  int  flags;
  npy_intp  *shape;
  npy_intp  *strides;
  void  *data;
  PyObject  *descr;
}  PyArrayInterface; 
int two

整数 2 作为一个健全性检查。

int nd

数组中的维数。

char typekind

根据类型字符串约定,指示存在何种类型数组的字符,‘t’ -> 位域,‘b’ -> 布尔值,‘i’ -> 有符号整数,‘u’ -> 无符号整数,‘f’ -> 浮点数,‘c’ -> 复数浮点数,‘O’ -> 对象,‘S’ -> (字节)字符串,‘U’ -> Unicode,‘V’ -> 空。

int itemsize

数组中每个项需要的字节数。

int flags

NPY_ARRAY_C_CONTIGUOUS (1), NPY_ARRAY_F_CONTIGUOUS (2), NPY_ARRAY_ALIGNED (0x100), NPY_ARRAY_NOTSWAPPED (0x200),或NPY_ARRAY_WRITEABLE (0x400),指示有关数据的一些信息。NPY_ARRAY_ALIGNEDNPY_ARRAY_C_CONTIGUOUSNPY_ARRAY_F_CONTIGUOUS标志实际上可以从其他参数中确定。标志NPY_ARR_HAS_DESCR (0x800)也可以设置为指示给消耗版本 3 数组接口的对象,这个结构的 descr 成员是存在的(对消耗版本 2 数组接口的对象会被忽略)。

*shape

包含每个维度中数组大小的数组。

*strides

包含每个维度中移动到下一个元素所需的字节数的数组。

void *data

数组的第一个元素的指针。

*descr

更详细描述数据类型的 Python 对象(与__array_interface__中的descr键相同)。如果typekinditemsize提供足够信息,则这可以是NULL。除非flags中打开了 NPY_ARR_HAS_DESCR 标志,否则也会忽略此字段。

内部使用的结构

内部,代码使用一些额外的 Python 对象主要用于内存管理。这些类型无法直接从 Python 访问,也不暴露给 C-API。它们在这里仅用于完整性和帮助理解代码。

type PyUFunc_Loop1d

一个包含为每个用户定义的数据类型的每个已定义签名定义 1-d 循环的信息的 C-结构的简单链接列表。

PyArrayMapIter_Type

高级索引由这种 Python 类型处理。它只是包装了包含高级数组索引所需变量的 C 结构的松散包装。

type PyArrayMapIterObject

PyArrayMapIter_Type相关联的 C 结构。如果您试图理解高级索引映射代码,这个结构很有用。它在arrayobject.h头文件中定义。这种类型不暴露给 Python,可以用 C 结构替换。作为 Python 类型,它利用了引用计数内存管理。

定义的新 Python 类型

Python 类型相当于 Python 中的类。通过构建一个新的 Python 类型,您可以为 Python 提供一个新对象。ndarray对象就是在 C 中定义的一个新类型的示例。定义新类型的基本步骤是:

  1. 创建一个与PyObject结构本身二进制兼容但包含特定对象所需的附加信息的 C 结构(通常命名为Py{Name}Object);

  2. 填充PyTypeObject表(由PyObject结构的 ob_type 成员指向的):指向实现该类型所需行为的函数的指针。

而不是为 Python 类定义行为的特殊方法名称,有指向实现所需结果的功能表。自 Python 2.2 以来,PyTypeObject本身已经变得动态,允许在 C 中“从其他 C 类型”继承的 C 类型,“在 Python 中子类化”。子类型从其父类型继承属性和方法。

有两个主要的新类型:ndarrayPyArray_Type )和ufuncPyUFunc_Type )。其他类型起辅助作用:PyArrayIter_TypePyArrayMultiIter_TypePyArrayDescr_TypePyArrayIter_Typendarray的平坦迭代器类型(在获取 flat 属性时返回的对象)。PyArrayMultiIter_Type是调用broadcast()时返回的对象类型。它处理迭代和广播集合的嵌套序列。另外,PyArrayDescr_Type是数据类型描述符类型,其实例描述数据。最后,还有 21 种新的标量数组类型,这些是对应于数组的可用基本数据类型的新 Python 标量。另外还有 10 种其他类型,这些是占位符,允许数组标量适应实际 Python 类型的层次结构。

PyArray_TypePyArrayObject

PyArray_Type

ndarray的 Python 类型是PyArray_Type。在 C 中,每个ndarray都是指向PyArrayObject结构体的指针。该结构体的ob_type成员包含一个指向PyArray_Type类型对象的指针。

type PyArrayObject
type NPY_AO

PyArrayObject C 结构体包含数组的所有必需信息。所有ndarray实例(及其子类)都将具有此结构。为了将来的兼容性,应使用提供的宏来访问这些结构成员。如果需要更短的名称,可以使用NPY_AO(已弃用),其定义等同于PyArrayObject。已弃用直接访问结构字段。请改为使用PyArray_*(arr)形式。从 NumPy 1.20 开始,这个结构的大小不被视为 NumPy ABI 的一部分(请参见成员列表末尾的说明)。

typedef  struct  PyArrayObject  {
  PyObject_HEAD
  char  *data;
  int  nd;
  npy_intp  *dimensions;
  npy_intp  *strides;
  PyObject  *base;
  PyArray_Descr  *descr;
  int  flags;
  PyObject  *weakreflist;
  /* version dependent private members */
}  PyArrayObject; 
PyObject_HEAD

这对所有 Python 对象都是必需的。它由(至少)一个引用计数成员(ob_refcnt)和一个指向类型对象(ob_type)的指针组成。(如果 Python 是使用特殊选项编译的,可能还有其他元素,请参见 Python 源代码树中的 Include/object.h 了解更多信息)。ob_type 成员指向 Python 类型对象。

char *data

可通过PyArray_DATA访问,此数据成员是数组的第一个元素的指针。这个指针可以(通常应该)重塑为数组的数据类型。

int nd

一个整数,提供此数组的维度数量。当 nd 为 0 时,该数组有时被称为 0 阶数组。这样的数组具有未定义的维度和跨度,无法访问。宏 PyArray_NDIMndarraytypes.h 中定义,指向这个数据成员。NPY_MAXDIMS 是任何数组的最大维度数量。

*dimensions

一个整数数组,为每个维度提供每个维度的形状,只要 nd (\geq) 1。整数总是足够大以容纳平台上的指针,因此维度大小仅受内存限制。PyArray_DIMS 是与这个数据成员相关联的宏。

*strides

一个整数数组,为每个维度提供跳过的字节数,以便在该维度中到达下一个元素。与宏 PyArray_STRIDES 相关联。

*base

PyArray_BASE 指向,这个成员用于保存与该数组相关的另一个 Python 对象的指针。有两种用例:

  • 如果这个数组不拥有自己的内存,那么 base 指向拥有它的 Python 对象(也许是另一个数组对象)。

  • 如果这个数组设置了 NPY_ARRAY_WRITEBACKIFCOPY 标志,那么这个数组是一个“行为异常”的数组的工作副本。

当调用 PyArray_ResolveWritebackIfCopy 时,将使用该数组的内容更新由 base 指向的数组。

*descr

一个指向数据类型描述对象的指针(参见下文)。数据类型描述对象是一个新的内置类型的实例,它允许对内存进行通用描述。每种支持的数据类型都有一个描述结构体。这个描述结构体包含有关该类型的有用信息,以及指向实现特定功能的函数指针表的指针。顾名思义,它与宏 PyArray_DESCR 相关联。

int flags

由宏 PyArray_FLAGS 指向,这个数据成员表示数据指向的内存应该如何解释的标志。可能的标志有 NPY_ARRAY_C_CONTIGUOUSNPY_ARRAY_F_CONTIGUOUSNPY_ARRAY_OWNDATANPY_ARRAY_ALIGNEDNPY_ARRAY_WRITEABLENPY_ARRAY_WRITEBACKIFCOPY

*weakreflist

这个成员允许数组对象具有弱引用(使用 weakref 模块)。

注意

进一步的成员被视为私有和版本相关。如果结构的大小对您的代码很重要,必须特别小心。当这是相关的可能使用案例是在 C 中进行子类化。如果您的代码依赖于sizeof(PyArrayObject)是恒定的,您必须在导入时添加以下检查:

if  (sizeof(PyArrayObject)  <  PyArray_Type.tp_basicsize)  {
  PyErr_SetString(PyExc_ImportError,
  "Binary incompatibility with NumPy, must recompile/update X.");
  return  NULL;
} 

要确保您的代码不必针对特定的 NumPy 版本进行编译,可以添加一个常量,为 NumPy 中的变化留出空间。 确保兼容任何未来的 NumPy 版本的解决方案需要运行时计算偏移量和分配大小。

PyArrayDescr_Type 和 PyArray_Descr

PyArrayDescr_Type

PyArrayDescr_Type 是用于描述组成数组的字节该如何解释的数据类型描述符对象的内置类型。有 21 个静态定义的PyArray_Descr对象用于内置数据类型。尽管这些参与引用计数,但它们的引用计数永远不应该为零。还维护了一个动态的用户定义的PyArray_Descr对象表。一旦“注册”了数据类型描述符对象,就不应该将其释放。函数PyArray_DescrFromType (…)可以用于从枚举类型号(内置或用户定义的)中检索PyArray_Descr对象。

type PyArray_Descr

PyArray_Descr 结构位于PyArrayDescr_Type的核心。虽然此处为完整起见进行了描述,但应将其视为 NumPy 的内部结构,并通过PyArrayDescr_*PyDataType*函数和宏来操作。此结构的大小可能会随 NumPy 的不同版本而发生变化。为确保兼容性:

  • 永远不要声明结构的非指针实例

  • 永远不要执行指针算术运算

  • 永远不要使用sizeof(PyArray_Descr)

它有以下结构:

typedef  struct  {
  PyObject_HEAD
  PyTypeObject  *typeobj;
  char  kind;
  char  type;
  char  byteorder;
  char  flags;
  int  type_num;
  int  elsize;
  int  alignment;
  PyArray_ArrayDescr  *subarray;
  PyObject  *fields;
  PyObject  *names;
  PyArray_ArrFuncs  *f;
  PyObject  *metadata;
  NpyAuxData  *c_metadata;
  npy_hash_t  hash;
}  PyArray_Descr; 
*typeobj

指向对应于此数组元素的 Python 类型的类型对象的指针。 对于内置类型,这指向对应的数组标量。 对于用户定义的类型,这应指向用户定义的类型对象。 这个类型对象可以继承自数组标量,也可以不继承。 如果它不继承自数组标量,那么flags成员中应该设置NPY_USE_GETITEMNPY_USE_SETITEM标志。

char kind

表示数组种类的字符代码(使用数组接口类型字符串表示法)。 'b'代表布尔值,'i'代表有符号整数,'u'代表无符号整数,'f'代表浮点数,'c'代表复数浮点数,'S'代表 8 位零终止字节,'U'代表 32 位/字符的 unicode 字符串,'V'代表任意长度。

char type

传统的字符代码,表示数据类型。

char byteorder

一个表示字节顺序的字符:‘>’(大端),‘<’(小端),‘=’(本机),‘|’(无关,忽略)。所有内置数据类型都具有字节顺序‘=’。

char flags

一个确定数据类型是否展示类似对象数组的行为的数据类型位标志。这个成员中的每个位是一个标志,它们被命名为:

  • NPY_ITEM_REFCOUNT

  • NPY_ITEM_HASOBJECT

  • NPY_LIST_PICKLE

  • NPY_ITEM_IS_POINTER

  • NPY_NEEDS_INIT

  • NPY_NEEDS_PYAPI

  • NPY_USE_GETITEM

  • NPY_USE_SETITEM

  • NPY_FROM_FIELDS

  • NPY_OBJECT_DTYPE_FLAGS

int type_num

一个唯一标识数据类型的数字。对于新数据类型,当数据类型被注册时,分配这个数字。

int elsize

对于始终相同大小的数据类型(例如 long),这个成员保存数据类型的大小。对于灵活的数据类型,不同的数组可能具有不同的元素大小,这个值应该为 0。

int alignment

提供这个数据类型的对齐信息的数字。具体来说,它显示编译器在一个 2 元结构的开始处(其第一个元素是一个char)放置该类型的项的距离:offsetof(struct {char c; type v;}, v)

*subarray

如果这是非NULL,那么这个数据类型描述符是另一个数据类型描述符的 C 风格连续数组。换句话说,这个描述符描述的每个元素实际上是另一个基本描述符的数组。这对于作为另一个数据类型描述符中字段的数据类型描述符最有用。如果这个非NULL,则 fields 成员应该为NULL(但是 base 描述符的 fields 成员可以为非NULL)。

type PyArray_ArrayDescr
typedef  struct  {
  PyArray_Descr  *base;
  PyObject  *shape;
}  PyArray_ArrayDescr; 
*base

基本类型的数据类型描述符对象。

*shape

子数组的形状(始终是 C 风格连续)作为 Python 元组。

*fields

如果这不是 NULL,则这个数据类型描述符具有由 Python 字典描述的字段,其键是名称(如果给定也是标题),其值是描述字段的元组。请记住,数据类型描述符总是描述一组固定长度的字节。字段是该总体固定长度集合的命名子区域。字段由另一个数据类型描述符和一个字节偏移的元组描述。可选地,元组可以包含通常是 Python 字符串的标题。这些元组被放在此字典中,以名称(如果给定也是标题)为键。

*names

字段名称的有序元组。如果未定义字段,则为 NULL。

*f

指向包含类型需要实现内部功能的函数的结构的指针。这些函数与后面描述的通用函数(ufuncs)不同。它们的签名可以任意变化。

*metadata

关于这个数据类型的元数据。

*c_metadata

特定于特定 dtype 的 C 实现的元数据。添加到 NumPy 1.7.0 中。

type npy_hash_t
*hash

当前未使用。保留用于将来缓存哈希值。

NPY_ITEM_REFCOUNT

表示这种数据类型的项必须进行引用计数(使用Py_INCREFPy_DECREF)。

NPY_ITEM_HASOBJECT

NPY_ITEM_REFCOUNT相同。

NPY_LIST_PICKLE

表示必须在将数组转储为列表之前将这种数据类型的数组转换为列表。

NPY_ITEM_IS_POINTER

表示该项是指向其他数据类型的指针

NPY_NEEDS_INIT

表示必须初始化此数据类型的内存(设置为 0)。

NPY_NEEDS_PYAPI

表明此数据类型在访问时需要 Python C-API(因此,在需要数组访问时不要放弃 GIL)。

NPY_USE_GETITEM

在数组访问时,使用f->getitem函数指针而不是标准的转换为数组标量。如果不定义与数据类型一起使用的数组标量,必须使用。

NPY_USE_SETITEM

从数组标量创建一个 0-d 数组时,请使用f->setitem而不是标准的从数组标量复制。如果不定义与数据类型一起使用的数组标量,必须使用。

NPY_FROM_FIELDS

如果数据类型的任何字段中设置了这些位,则从父数据类型继承的位。目前(NPY_NEEDS_INIT | NPY_LIST_PICKLE | NPY_ITEM_REFCOUNT | NPY_NEEDS_PYAPI)。

NPY_OBJECT_DTYPE_FLAGS

对象数据类型的设置位:(NPY_LIST_PICKLE | NPY_USE_GETITEM | NPY_ITEM_IS_POINTER | NPY_ITEM_REFCOUNT | NPY_NEEDS_INIT | NPY_NEEDS_PYAPI)。

int PyDataType_FLAGCHK( *dtype, int flags)

如果对于数据类型对象设置了所有给定的标志,则返回 true。

int PyDataType_REFCHK( *dtype)

等效于PyDataType_FLAGCHKdtypeNPY_ITEM_REFCOUNT)。

type PyArray_ArrFuncs

实现内部功能的函数。并非所有这些函数指针必须对给定类型进行定义。所需成员是nonzerocopyswapcopyswapnsetitemgetitemcast。假定这些都是非NULL的,而NULL条目将导致程序崩溃。其他函数可能是NULL,这意味着该数据类型的功能将减少。 (同时,如果在注册用户定义的数据类型时NULL,则nonzero函数将填充为默认函数)。

typedef  struct  {
  PyArray_VectorUnaryFunc  *cast[NPY_NTYPES];
  PyArray_GetItemFunc  *getitem;
  PyArray_SetItemFunc  *setitem;
  PyArray_CopySwapNFunc  *copyswapn;
  PyArray_CopySwapFunc  *copyswap;
  PyArray_CompareFunc  *compare;
  PyArray_ArgFunc  *argmax;
  PyArray_DotFunc  *dotfunc;
  PyArray_ScanFunc  *scanfunc;
  PyArray_FromStrFunc  *fromstr;
  PyArray_NonzeroFunc  *nonzero;
  PyArray_FillFunc  *fill;
  PyArray_FillWithScalarFunc  *fillwithscalar;
  PyArray_SortFunc  *sort[NPY_NSORTS];
  PyArray_ArgSortFunc  *argsort[NPY_NSORTS];
  PyObject  *castdict;
  PyArray_ScalarKindFunc  *scalarkind;
  int  **cancastscalarkindto;
  int  *cancastto;
  PyArray_FastClipFunc  *fastclip;  /* deprecated */
  PyArray_FastPutmaskFunc  *fastputmask;  /* deprecated */
  PyArray_FastTakeFunc  *fasttake;  /* deprecated */
  PyArray_ArgFunc  *argmin;
}  PyArray_ArrFuncs; 

"表现正常"的概念用于描述函数指针。一个表现正常的段是指对齐且符合数据类型本机字节顺序的段。nonzerocopyswapcopyswapngetitemsetitem函数可以(而且必须)处理不正常的数组。其他函数要求内存段表现正常。

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

一串函数指针,用于将当前类型向所有其他内置类型转换。每个函数将一个由from指向的连续、对齐、未交换的缓冲区转换为一个由to指向的连续、对齐和未交换的缓冲区。要转换的项数由n给出,参数fromarrtoarr被解释为灵活数组的 PyArrayObjects 以获取 itemsize 信息。

*getitem(void *data, void *arr)

一个指向从由data指向的数组对象arr的单个元素返回标准 Python 对象的函数的指针。这个函数必须能够正确处理“不正常”(不对齐和/或交换)的数组。

int setitem( *item, void *data, void *arr)

一个指向将 Python 对象item设置到由data指向的数组arr中的函数的指针。这个函数处理“不正常的”数组。如果成功,返回值为零,否则返回一个负数(并设置一个 Python 错误)。

void copyswapn(void *dest, dstride, void *src, sstride, n, int swap, void *arr)
void copyswap(void *dest, void *src, int swap, void *arr)

这些成员都是指向从src复制数据到dest并在需要时进行swap的函数的指针。arr 的值仅用于灵活(NPY_STRINGNPY_UNICODENPY_VOID)数组(并且从arr->descr->elsize中获取)。第二个函数复制单个值,而第一个函数使用提供的步幅循环 n 次。这些函数可以处理不正常的src数据。如果src为 NULL,则不执行复制。如果swap为 0,则不进行字节交换。假定destsrc不重叠。如果它们重叠,则首先使用memmove(…),然后使用带有空值srccopyswap(n)

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

一个指向比较数组arr中由d1d2指向的两个元素的函数的指针。这个函数要求数组表现正常(对齐并且没有交换)。如果* d1 > * d2,返回值为 1;如果* d1 == * d2,返回值为 0;如果* d1 < * d2,返回值为-1。数组对象arr用于获取灵活数组的 itemsize 和字段信息。

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

一个指向从由data指向的元素开始的arrn个元素中最大值的索引的函数的指针。这个函数要求内存段是连续的并且表现正常。返回值总是 0。最大元素的索引存储在max_ind中。

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

指向一个函数的指针,用于将两个长度为n的序列相乘,并将它们相加,然后将结果放在arrop指向的元素中。两个序列的起始位置分别由ip1ip2指向。要达到每个序列的下一个元素,需要分别跳过is1is2 字节。此函数需要被认为是行为良好的(尽管不一定连续)内存。

int scanfunc(FILE *fd, void *ip, void *arr)

指向一个函数的指针,用于从文件描述符fd中以(scanf 风格)扫描相应类型的元素到ip指向的数组内存中。假定该数组是被认为是行为良好的。最后一个参数arr是要扫描到的数组。返回成功分配的接收参数的数量(如果在分配第一个接收参数之前发生匹配失败,这个数量可能为零),或者在分配第一个接收参数之前发生输入失败时返回 EOF。在报告错误时应该在不持有 Python GIL 的情况下调用此函数,并且会为错误报告而调用 GIL。

int fromstr(char *str, void *ip, char **endptr, void *arr)

指向一个函数的指针,用于将由str指向的字符串转换为相应类型的一个元素,并将其放入ip指向的内存位置。转换完成后,*endptr指向字符串的其余部分。最后一个参数arr是 ip 指向的数组(对于可变大小数据类型是必需的)。成功返回 0,失败返回-1。需要一个被认为是行为良好的数组。在报告错误时应该在不持有 Python GIL 的情况下调用此函数,并且会为错误报告而调用 GIL。

nonzero(void *data, void *arr)

指向一个函数的指针,如果data指向的arr项是非零则返回 TRUE。此函数可以处理行为不良的数组。

void fill(void *data, length, void *arr)

指向一个函数的指针,用于用数据填充给定长度的连续数组。数组的前两个元素必须已经填充了值。从这两个值中,将计算出一个增量,并且从第 3 个到最后一个元素将会反复地加上这个计算出的增量。数据缓冲区必须是行为良好的。

void fillwithscalar(void *buffer, length, void *value, void *arr)

指向一个函数的指针,用于使用给定的单一标量值向长度为给定length的连续buffer填充数据。最后一个参数是所需的用于变长数组获取 itemsize 的数组。

int sort(void *start, length, void *arr)

一个指向特定排序算法的函数指针数组。使用键(到目前为止已经定义了NPY_QUICKSORTNPY_HEAPSORT,和NPY_MERGESORT)可以获取特定的排序算法。这些排序是就地进行的,假定数据是连续的和对齐的。

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

一个指向用于此数据类型的排序算法的函数指针数组。与 sort 相同的排序算法可用。产生排序的索引将会返回在result中(必须初始化为包含 0 到length-1的索引)。

*castdict

要么为NULL,要么是包含用户定义数据类型的低级转换函数的字典。每个函数都被包装在一个PyCapsule*中,并由数据类型编号键入。

scalarkind( *arr)

用于确定应如何解释此类型标量的函数。参数为NULL或包含数据的 0 维数组(如果需要确定标量类型)。返回值必须是NPY_SCALARKIND类型。

int **cancastscalarkindto

要么为NULL,要么为NPY_SCALARKINDS指针数组。这些指针应该是NULL,或者指向整数数组(以NPY_NOTYPE结尾),表示此数据类型的标量可以安全转换为指定类型的数据类型(通常表示不会失去精度)。

int *cancastto

要么为NULL,要么为整数数组(以NPY_NOTYPE结尾),表示此数据类型可以安全转换为的数据类型(通常表示不会失去精度)。

void fastclip(void *in, n_in, void *min, void *max, void *out)

自版本 1.17 起弃用:使用此函数将在np.clip时产生弃用警告。该数据类型必须使用PyUFunc_RegisterLoopForDescr来将自定义循环附加到np.core.umath.clipnp.minimumnp.maximum

自版本 1.19 起弃用:设置此函数已被弃用,应始终为NULL,如果设置,将被忽略。

一个函数,从in中读取n_in个项目,并将读取的值写入out,如果在minmax指向的限制范围内,则在外部使用对应的限制。内存段必须是连续的且规范化的,并且minmax可能为NULL,但不能同时为NULL

void fastputmask(void *in, void *mask, n_in, void *values, nv)

自版本 1.19 起弃用:设置此函数已被弃用,应始终为NULL,如果设置,将被忽略。

一个函数,接受指向n_in个项目数组的指针in,指向n_in个布尔值的数组的指针mask,以及指向nv个项目的数组的指针vals。无需失去精度地将vals中的项复制到in中,只需在mask中的值非零时,根据需要平铺vals,如果nv < n_in。所有数组都必须是连续的且规范化的。

void fasttake(void *dest, void *src, *indarray, nindarray, n_outer, m_middle, nelem, clipmode)

自版本 1.19 起弃用:设置此函数已被弃用,应始终为NULL,如果设置,将被忽略。

一个函数,它接受一个指向 C 连续、行为良好的段src,解释为形状为(n_outer, nindarray, nelem)的三维数组的指针,一个指向m_middle整数索引的连续的、行为良好的段indarray的指针,以及一个指向 C 连续、行为良好的段的指针dest,解释为形状为(n_outer, m_middle, nelem)的三维数组。indarray中的索引用于沿着第二维对src进行索引,并将相应的nelem项的块复制到dest中。clipmode(可以取值NPY_RAISENPY_WRAPNPY_CLIP


一个指针,指向一个函数,用于检索`data`指向的开始于`arr`的`n`个元素中最小元素的索引。此函数要求内存段是连续的且行为良好。返回值始终为 0。最小元素的索引存储在`min_ind`中。

`PyArray_Type` 类型对象实现了许多[`Python 对象`](https://docs.python.org/3/c-api/type.html#c.PyTypeObject "(in Python v3.11)")的特性,包括[`tp_as_number`](https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_as_number "(in Python v3.11)")、[`tp_as_sequence`](https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_as_sequence "(in Python v3.11)")、[`tp_as_mapping`](https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_as_mapping "(in Python v3.11)")和[`tp_as_buffer`](https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_as_buffer "(in Python v3.11)")接口。还使用了[`rich comparison`](https://docs.python.org/3/c-api/typeobj.html#c.richcmpfunc "(in Python v3.11)"),以及新式属性查找用于成员([`tp_members`](https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_members "(in Python v3.11)"))和属性([`tp_getset`](https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_getset "(in Python v3.11)"))。`PyArray_Type` 也可以被子类型化。

提示

`tp_as_number`方法使用一种通用方法来调用已注册用于处理操作的任何函数。导入`_multiarray_umath`模块时,它将为所有数组设置相应的 ufunc 数值操作。这个选择可以使用`PyUFunc_ReplaceLoopBySignature`进行更改。还可以使用`PyArray_SetStringFunction`更改`tp_str`和`tp_repr`方法。

### PyUFunc_Type 和 PyUFuncObject

```py
PyUFunc_Type

ufunc 对象是通过创建PyUFunc_Type来实现的。它是一个非常简单的类型,仅实现了基本的 getattribute 行为、打印行为,并具有调用行为,使这些对象可以像函数一样工作。ufunc 背后的基本思想是存储每种支持操作的数据类型的快速一维(向量)循环的引用. 所有这些一维循环都有相同的标识并且是创建新 ufunc 的关键。它们由通用循环代码在适当时调用以实现 N 维功能。还为浮点和复数浮点数组定义了一些通用的 1-d 循环,使您可以使用单个标量函数(例如atanh)来定义一个 ufunc。

type PyUFuncObject

ufunc 的核心是PyUFuncObject,它包含调用执行实际工作的底层 C 代码循环所需的所有信息。虽然这里对其进行了描述以便完整,但应该将其视为 NumPy 的内部部分,并通过PyUFunc_*函数进行操作。该结构的大小可能会随着 NumPy 版本的更改而改变。为确保兼容性:

  • 永远不要声明结构的非指针实例

  • 永远不要执行指针算术

  • 永远不要使用sizeof(PyUFuncObject)

它具有以下结构:

typedef  struct  {
  PyObject_HEAD
  int  nin;
  int  nout;
  int  nargs;
  int  identity;
  PyUFuncGenericFunction  *functions;
  void  **data;
  int  ntypes;
  int  reserved1;
  const  char  *name;
  char  *types;
  const  char  *doc;
  void  *ptr;
  PyObject  *obj;
  PyObject  *userloops;
  int  core_enabled;
  int  core_num_dim_ix;
  int  *core_num_dims;
  int  *core_dim_ixs;
  int  *core_offsets;
  char  *core_signature;
  PyUFunc_TypeResolutionFunc  *type_resolver;
  PyUFunc_LegacyInnerLoopSelectionFunc  *legacy_inner_loop_selector;
  void  *reserved2;
  npy_uint32  *op_flags;
  npy_uint32  *iter_flags;
  /* new in API version 0x0000000D */
  npy_intp  *core_dim_sizes;
  npy_uint32  *core_dim_flags;
  PyObject  *identity_value;
  /* Further private slots (size depends on the NumPy version) */
}  PyUFuncObject; 
int nin

输入参数的数量。

int nout

输出参数的数量。

int nargs

参数的总数(nin + nout)。这个必须小于NPY_MAXARGS

int identity

使用PyUFunc_OnePyUFunc_ZeroPyUFunc_MinusOnePyUFunc_NonePyUFunc_ReorderableNonePyUFunc_IdentityValue来指示此操作的标识。它仅在对空数组进行类似缩减的调用时使用。

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

一个函数指针数组,每一种数据类型都有一个。这个向量循环用于实现底层函数dims[0]次。第一个参数args是一个具有nargs指针的数组,指向行为良好的内存。首先是指向输入参数数据的指针,然后是指向输出参数数据的指针。必须跳过多少字节才能到达序列中的下一个元素由steps数组中的相应条目指定。最后一个参数允许循环接收额外的信息。这通常是为了使单个通用向量循环用于多个函数。在这种情况下,要调用的实际标量函数以extradata的形式传递。此函数指针数组的大小为 ntypes。

void **data

传递给 1 维向量循环的额外数据,如果不需要额外数据,则为NULL。这个 C 数组的大小必须与函数数组相同(即 ntypes)。如果不需要 extra_data,则使用NULL。一些用于 UFuncs 的 C-API 调用只是 1 维向量循环,利用这些额外数据来接收要调用的实际函数的指针。

int ntypes

Ufunc 支持的数据类型数。此数字指定有多少不同的 1 维循环(内置数据类型)可用。

int reserved1

未使用。

char *name

Ufunc 的字符串名称。这个动态用于构建 ufunc 的 doc 属性。

char *types

一个(nargs \times ntypes)的 8 位 type_numbers 数组,其中包含每个支持的(内置)数据类型的函数的类型签名。对于ntypes个函数中的每一个,该数组中相应的一组类型编号显示了如何在 1 维向量循环中解释args参数。这些类型编号不必是相同的类型,支持混合类型的 ufunc。

char *doc

UFunc 的文档。不应包含函数签名,因为这在检索 doc 时动态生成。

void *ptr

任何动态分配的内存。目前,这用于从 python 函数创建的动态 ufunc 中存储类型、数据和名称成员的空间。

*obj

对于从 python 函数动态创建的 ufunc,此成员保存对底层 Python 函数的引用。

*userloops

用户定义的 1 维向量循环的字典(存储为 CObject ptrs),用于用户定义的类型。用户可以为任何用户定义的类型注册循环。它通过类型编号检索。用户定义的类型编号始终大于NPY_USERDEF

int core_enabled

标量 ufunc 的为 0;广义 ufunc 的为 1。

int core_num_dim_ix

签名中的不同核心维度名称数

int *core_num_dims

每个参数的核心维度数

int *core_dim_ixs

展平形式的维度索引;参数k的索引存储在core_dim_ixs[core_offsets[k] : core_offsets[k] + core_numdims[k]]

int *core_offsets

每个参数在core_dim_ixs中的第一个核心维度的位置,相当于 cumsum(core_num_dims)

char *core_signature

核心签名字符串

PyUFunc_TypeResolutionFunc *type_resolver

解析类型并填充一个数组以获取输入和输出的 dtype 的函数

PyUFunc_LegacyInnerLoopSelectionFunc *legacy_inner_loop_selector

自版本 1.22 起弃用:该插槽的一些回退支持存在,但最终将被移除。依赖于此的通用函数最终将必须进行移植。参见NEP 41NEP 43

void *reserved2

对于可能的具有不同签名的未来循环选择器。

op_flags

覆盖每个 ufunc 操作数的默认操作数标志。

iter_flags

覆盖 ufunc 的默认 nditer 标志。

在 API 版本 0x0000000D 中添加

*core_dim_sizes

对于每个不同的核心维度,如果UFUNC_CORE_DIM_SIZE_INFERRED0,则可能为冻结大小

*core_dim_flags

对于每个不同的核心维度,一组标志(UFUNC_CORE_DIM_CAN_IGNOREUFUNC_CORE_DIM_SIZE_INFERRED)

*identity_value

缩减的身份,当PyUFuncObject.identity等于PyUFunc_IdentityValue时。

UFUNC_CORE_DIM_CAN_IGNORE

如果维度名称以?结尾

UFUNC_CORE_DIM_SIZE_INFERRED

如果维度大小将根据操作数确定而不是来自冻结签名

PyArrayIter_Type 和 PyArrayIterObject

PyArrayIter_Type

这是一个迭代器对象,可以轻松地循环遍历 N 维数组。它是从 ndarray 的 flat 属性返回的对象。它还广泛地用于实现内部,以便循环遍历 N 维数组。实现了 tp_as_mapping 接口,以便可以索引迭代器对象(使用 1-d 索引),并且通过 tp_methods 表实现了一些方法。这个对象实现了 next 方法,并且可以在 Python 中的任何地方使用迭代器。

type PyArrayIterObject

PyArrayIter_Type对象对应的 C 结构是PyArrayIterObjectPyArrayIterObject用于跟踪 N 维数组中的指针。它包含用于快速遍历数组的相关信息。指针可以通过三种基本方式进行调整:1)以 C 样式的连续方式前进到数组中的“下一个”位置,2)前进到数组中的任意 N 维坐标,3)前进到数组中的任意一维索引。PyArrayIterObject结构的成员用于进行这些计算。迭代器对象保留有关数组的自己的维度和跨度信息。这可根据需要进行调整,以进行“广播”,或仅在特定维度上循环。

typedef  struct  {
  PyObject_HEAD
  int  nd_m1;
  npy_intp  index;
  npy_intp  size;
  npy_intp  coordinates[NPY_MAXDIMS];
  npy_intp  dims_m1[NPY_MAXDIMS];
  npy_intp  strides[NPY_MAXDIMS];
  npy_intp  backstrides[NPY_MAXDIMS];
  npy_intp  factors[NPY_MAXDIMS];
  PyArrayObject  *ao;
  char  *dataptr;
  npy_bool  contiguous;
}  PyArrayIterObject; 
int nd_m1

(N-1),其中(N)是底层数组中的维数。

index

到数组的当前一维索引。

size

底层数组的总大小。

*coordinates

到数组的(N) -维索引。

*dims_m1

每个维度中数组大小减 1。

*strides

数组的跨度。在每个维度中跳到下一个元素需要多少字节。

*backstrides

从维度末尾跳回到开头需要多少字节。注意backstrides[k] == strides[k] * dims_m1[k],但它被存储在这里作为一种优化。

*factors

该数组用于从一维索引计算 N 维索引。它包含所需的维度的乘积。

*ao

指向此迭代器被创建以代表的基础 ndarray 的指针。

char *dataptr

此成员指向由索引指示的 ndarray 中的一个元素。

contiguous

如果底层数组是NPY_ARRAY_C_CONTIGUOUS,则此标志为 true。它用于在可能的情况下简化计算。

如何在 C 级别上使用数组迭代器在后续章节中有更详细的解释。通常情况下,您不需要关心迭代器对象的内部结构,只需通过宏PyArray_ITER_NEXT (it)、PyArray_ITER_GOTO (it, dest)或者PyArray_ITER_GOTO1D (it, index)来与之交互即可,所有这些宏要求参数it是 PyArrayIterObject*。

PyArrayMultiIter_Type 和 PyArrayMultiIterObject

PyArrayMultiIter_Type

这种类型提供了一种封装广播概念的迭代器。它允许将(N)个数组一起广播,使得循环按照广播数组的 C 风格连续方式进行。相应的 C 结构是PyArrayMultiIterObject,其内存布局必须从任何传递给PyArray_Broadcast (obj)函数的对象obj开始。通过调整数组迭代器执行广播,使得每个迭代器表示广播的形状和大小,但其步幅调整为每次迭代中使用数组的正确元素。

type PyArrayMultiIterObject
typedef  struct  {
  PyObject_HEAD
  int  numiter;
  npy_intp  size;
  npy_intp  index;
  int  nd;
  npy_intp  dimensions[NPY_MAXDIMS];
  PyArrayIterObject  *iters[NPY_MAXDIMS];
}  PyArrayMultiIterObject; 
int numiter

需要广播到相同形状的数组的数量。

size

广播的总大小。

index

广播结果的当前(1-D)索引。

int nd

广播结果中的维数。

*dimensions

广播结果的形状(仅使用nd个插槽)。

**iters

一个迭代器对象数组,其中包含要合并广播的数组的迭代器。返回时,这些迭代器已调整为进行广播。

PyArrayNeighborhoodIter_Type 和 PyArrayNeighborhoodIterObject

PyArrayNeighborhoodIter_Type

这是一个迭代器对象,它可以轻松地在 N 维邻域上循环。

type PyArrayNeighborhoodIterObject

PyArrayNeighborhoodIter_Type对象对应的 C 结构是PyArrayNeighborhoodIterObject

typedef  struct  {
  PyObject_HEAD
  int  nd_m1;
  npy_intp  index,  size;
  npy_intp  coordinates[NPY_MAXDIMS]
  npy_intp  dims_m1[NPY_MAXDIMS];
  npy_intp  strides[NPY_MAXDIMS];
  npy_intp  backstrides[NPY_MAXDIMS];
  npy_intp  factors[NPY_MAXDIMS];
  PyArrayObject  *ao;
  char  *dataptr;
  npy_bool  contiguous;
  npy_intp  bounds[NPY_MAXDIMS][2];
  npy_intp  limits[NPY_MAXDIMS][2];
  npy_intp  limits_sizes[NPY_MAXDIMS];
  npy_iter_get_dataptr_t  translate;
  npy_intp  nd;
  npy_intp  dimensions[NPY_MAXDIMS];
  PyArrayIterObject*  _internal_iter;
  char*  constant;
  int  mode;
}  PyArrayNeighborhoodIterObject; 

PyArrayFlags_Type 和 PyArrayFlagsObject

PyArrayFlags_Type

当从 Python 检索 flags 属性时,会构造一个特殊的内置对象的此类型。这种特殊的类型使得通过访问它们作为属性或者假定对象是一个以标志名称为条目的字典而访问它们来更容易地处理不同的标志。

type PyArrayFlagsObject
typedef  struct  PyArrayFlagsObject  {
  PyObject_HEAD
  PyObject  *arr;
  int  flags;
}  PyArrayFlagsObject; 

标量数组类型

数组中可能出现的不同内置数据类型都有对应的 Python 类型。其中大多数类型只是对应的 C 语言数据类型的简单封装。这些类型在 C 语言中的名称为 Py{TYPE}ArrType_Type,其中 {TYPE} 可以是

BoolByteShortIntLongLongLongUByteUShortUIntULongULongLongHalfFloatDoubleLongDoubleCFloatCDoubleCLongDoubleStringUnicodeVoidObject

这些类型名称属于 C-API 的一部分,因此可以在扩展 C 代码中创建。还有一个 PyIntpArrType_TypePyUIntpArrType_Type,它们是平台上可以保存指针的整数类型的简单替代品。这些标量对象的结构对 C 代码不可见。函数 PyArray_ScalarAsCtype (..) 可以用于从数组标量中提取 C 类型值,而函数 PyArray_Scalar (…) 可以用于从 C 值构造一个数组标量。

- PyArray_TypePyArrayObject

PyArray_Type

ndarray 的 Python 类型是PyArray_Type。在 C 中,每个 ndarray 都是一个指向 PyArrayObject 结构的指针。这个结构的 ob_type 成员包含一个指向 PyArray_Type 类型对象的指针。

type PyArrayObject
type NPY_AO

PyArrayObject C 结构包含数组的所有必要信息。所有 ndarray(及其子类)的实例都具有这一结构。为了未来的兼容性,应该使用提供的宏来访问这些结构成员。如果需要更短的名称,那么可以使用 NPY_AO(已弃用),它被定义为等同于 PyArrayObject。直接访问结构字段已被弃用。请改用 PyArray_*(arr) 形式。从 NumPy 1.20 开始,此结构的大小不被认为是 NumPy ABI 的一部分(请参见成员列表末尾的注释)。

typedef  struct  PyArrayObject  {
  PyObject_HEAD
  char  *data;
  int  nd;
  npy_intp  *dimensions;
  npy_intp  *strides;
  PyObject  *base;
  PyArray_Descr  *descr;
  int  flags;
  PyObject  *weakreflist;
  /* version dependent private members */
}  PyArrayObject; 
PyObject_HEAD

这适用于所有 Python 对象。它至少包含一个引用计数成员( ob_refcnt )和一个类型对象指针( ob_type )。(如果使用特殊选项编译 Python,可能还有其他成员,请参见 Python 源代码树中的 Include/object.h 获取更多信息。)ob_type 成员指向一个 Python 类型对象。

char *data

通过 PyArray_DATA 可以访问到这个数据成员,它是数组的第一个元素的指针。这个指针可以(通常应该)被重新解释为数组的数据类型。

int nd

为此数组提供维数的整数。当 nd 为 0 时,有时称该数组为秩为 0 的数组。这样的数组具有未定义的维度和步幅,并且无法访问。宏 PyArray_NDIMndarraytypes.h 中定义,指向此数据成员。NPY_MAXDIMS 是任何数组的最大维数。

*dimensions

一个提供每个维度的形状的整数数组,只要 nd (\geq) 1. 该整数始终足够大,以容纳平台上的指针,因此维度大小仅受内存限制。PyArray_DIMS 是与此数据成员关联的宏。

*strides

为每个维度提供一个整数数组,指定必须跳过多少字节才能到达该维度中的下一个元素。与宏PyArray_STRIDES 相关。

*base

PyArray_BASE 指向,此成员用于保存指向与此数组相关的另一个 Python 对象的指针。有两种用法:

  • 如果该数组不拥有自己的内存,则 base 指向拥有它的 Python 对象(也许是另一个数组对象)。

  • 如果此数组设置了NPY_ARRAY_WRITEBACKIFCOPY 标志,则此数组是“行为不端”数组的工作副本。

当调用 PyArray_ResolveWritebackIfCopy 时,base 指向的数组将使用此数组的内容进行更新。

*descr

指向数据类型描述符对象的指针(见下文)。数据类型描述符对象是一种新的内置类型的实例,允许对内存进行通用描述。对于支持的每种数据类型都有一个描述符结构。此描述符结构包含有关类型的有用信息以及实现特定功能的函数指针表的指针。正如名称所示,它与宏PyArray_DESCR 相关联。

int flags

由宏PyArray_FLAGS 指向的,这个数据成员表示标志,指示由 data 指向的内存应如何解释。可能的标志有NPY_ARRAY_C_CONTIGUOUSNPY_ARRAY_F_CONTIGUOUSNPY_ARRAY_OWNDATANPY_ARRAY_ALIGNEDNPY_ARRAY_WRITEABLENPY_ARRAY_WRITEBACKIFCOPY

*weakreflist

此成员允许数组对象具有弱引用(使用 weakref 模块)。

注意

进一步的成员被视为私有和版本相关的。如果结构的大小对您的代码很重要,则必须特别小心。当这一点是相关的时候可能的用例是在 C 中进行子类化。如果您的代码依赖于sizeof(PyArrayObject)是常量,您必须在导入时添加以下检查:

if  (sizeof(PyArrayObject)  <  PyArray_Type.tp_basicsize)  {
  PyErr_SetString(PyExc_ImportError,
  "Binary incompatibility with NumPy, must recompile/update X.");
  return  NULL;
} 

为了确保您的代码不必为特定的 NumPy 版本编译,您可以添加一个常量,为 NumPy 的更改留出空间。一个确保与任何未来 NumPy 版本兼容的解决方案需要使用运行时计算偏移和分配大小。

PyArrayDescr_Type 和 PyArray_Descr

PyArrayDescr_Type

PyArrayDescr_Type是用于描述如何解释组成数组的字节的数据类型描述符对象的内置类型。有 21 个静态定义的PyArray_Descr对象用于内置数据类型。虽然它们参与引用计数,但它们的引用计数永远不应该达到零。还有一个动态的用户定义的PyArray_Descr对象表也在维护中。一旦数据类型描述符对象被“注册”,就不应该被释放。函数PyArray_DescrFromType(…)可以用于从枚举类型编号(内置或用户定义的)检索PyArray_Descr对象。

type PyArray_Descr

PyArray_Descr结构位于PyArrayDescr_Type的核心。虽然这里对其进行了描述以保持完整性,但应该将其视为 NumPy 的内部结构,并通过PyArrayDescr_*PyDataType*函数和宏来操作。此结构的大小可能会随 NumPy 版本的变化而变化。为了确保兼容性:

  • 永远不要声明结构的非指针实例

  • 永远不要进行指针算术运算

  • 永远不要使用 sizeof(PyArray_Descr)

它具有以下结构:

typedef  struct  {
  PyObject_HEAD
  PyTypeObject  *typeobj;
  char  kind;
  char  type;
  char  byteorder;
  char  flags;
  int  type_num;
  int  elsize;
  int  alignment;
  PyArray_ArrayDescr  *subarray;
  PyObject  *fields;
  PyObject  *names;
  PyArray_ArrFuncs  *f;
  PyObject  *metadata;
  NpyAuxData  *c_metadata;
  npy_hash_t  hash;
}  PyArray_Descr; 
*typeobj

指向与此数组元素对应的 Python 类型的类型对象的指针。对于内置类型,这指向相应的数组标量。对于用户定义的类型,这应该指向用户定义的类型对象。这个类型对象可以继承自数组标量,也可以不继承。如果它不继承自数组标量,则flags成员中应设置NPY_USE_GETITEMNPY_USE_SETITEM标志。

char kind

表示数组种类的字符代码(使用数组接口类型字符串表示法)。‘b’表示布尔,‘i’表示有符号整数,‘u’表示无符号整数,‘f’表示浮点数,‘c’表示复数浮点数,‘S’表示 8 位以零结尾的字节,‘U’表示 32 位/字符的 Unicode 字符串,‘V’表示任意。

char type

表示数据类型的传统字符代码。

char byteorder

表示字节顺序的字符:‘>’(大端)、‘<’(小端)、‘=’(本地)、‘|’(不相关,忽略)。所有内置数据类型的字节顺序都是‘=’。

char flags

一个数据类型位标志,确定数据类型是否表现出对象数组的行为。该成员中的每个位都是一个标志,命名为:

  • NPY_ITEM_REFCOUNT

  • NPY_ITEM_HASOBJECT

  • NPY_LIST_PICKLE

  • NPY_ITEM_IS_POINTER

  • NPY_NEEDS_INIT

  • NPY_NEEDS_PYAPI

  • NPY_USE_GETITEM

  • NPY_USE_SETITEM

  • NPY_FROM_FIELDS

  • NPY_OBJECT_DTYPE_FLAGS

int type_num

一个唯一标识数据类型的数字。对于新数据类型,当数据类型被注册时,会分配这个数字。

int elsize

对于始终大小相同的数据类型(例如 long),这保存数据类型的大小。对于灵活的数据类型,其中不同的数组可以具有不同的元素大小,这应为 0。

int alignment

为此数据类型提供对齐信息的数字。具体来说,它显示了编译器将该类型的项目放置在起始为 char 的 2 元结构中的距离:offsetof(struct {char c; type v;}, v)

*subarray

如果这是非 NULL,那么这个数据类型描述符是另一个数据类型描述符的 C 风格连续数组。换句话说,这个描述符描述的每个元素实际上都是另一个基本描述符的数组。这在作为另一个数据类型描述符中的字段的数据类型描述符时最有用。如果这是非 NULL,则 fields 成员应为 NULL(但基本描述符的 fields 成员可以是非 NULL)。

type PyArray_ArrayDescr
typedef  struct  {
  PyArray_Descr  *base;
  PyObject  *shape;
}  PyArray_ArrayDescr; 
*base

基础类型的数据类型描述符对象。

*shape

作为 Python 元组的子数组的形状(始终是 C 风格连续的)。

*fields

如果这是非 NULL,则此数据类型描述符具有由 Python 字典描述的字段,其键是名称(如果给定也是标题),其值是描述字段的元组。回想一下,数据类型描述符总是描述一组固定长度的字节。字段是该总体、固定长度的集合的命名子区域。字段由另一个数据类型描述符和字节偏移量组成的元组描述。可选地,元组可以包含一个标题,通常是 Python 字符串。这些元组被放置在此字典中,键为名称(如果给定也是标题)。

*names

一个有序的字段名称元组。如果未定义字段,则为 NULL。

*f

指向包含类型需要实现内部功能的函数的结构体指针。这些函数与后面描述的通用函数(ufuncs)不是同一种东西。它们的签名可以任意变化。

*metadata

关于此数据类型的元数据。

*c_metadata

特定于特定数据类型的 C 实现的元数据。添加于 NumPy 1.7.0。

type npy_hash_t
*hash

目前未使用。保留以缓存散列值的未来使用。

NPY_ITEM_REFCOUNT

表明此数据类型的项目必须进行引用计数(使用Py_INCREFPy_DECREF)。

NPY_ITEM_HASOBJECT

NPY_ITEM_REFCOUNT相同。

NPY_LIST_PICKLE

表示此数据类型的数��必须在 pickling 之前转换为列表。

NPY_ITEM_IS_POINTER

表示项目是指向其他数据类型的指针。

NPY_NEEDS_INIT

表示此数据类型的内存在创建时必须初始化(设置为 0)。

NPY_NEEDS_PYAPI

表明此数据类型在访问时需要 Python C-API(因此如果需要数组访问,则不要放弃 GIL)。

NPY_USE_GETITEM

在数组访问中,使用f->getitem函数指针,而不是标准的转换为数组标量。如果没有定义与数据类型相配套的数组标量,则必须使用。

NPY_USE_SETITEM

从数组标量创建 0 维数组时,请使用f->setitem,而不是标准的从数组标量复制。如果没有定义与数据类型相匹配的数组标量,则必须使用。

NPY_FROM_FIELDS

如果这些位在数据类型的任何字段中设置,那么这些位就会继承自父数据类型。当前(NPY_NEEDS_INIT | NPY_LIST_PICKLE | NPY_ITEM_REFCOUNT | NPY_NEEDS_PYAPI)。

NPY_OBJECT_DTYPE_FLAGS

为对象数据类型设置的位:(NPY_LIST_PICKLE | NPY_USE_GETITEM | NPY_ITEM_IS_POINTER | NPY_ITEM_REFCOUNT | NPY_NEEDS_INIT | NPY_NEEDS_PYAPI)。

int PyDataType_FLAGCHK( *dtype, int flags)

如果数据类型对象上设置了给定标志,则返回 true。

int PyDataType_REFCHK( *dtype)

等同于PyDataType_FLAGCHKdtype, NPY_ITEM_REFCOUNT)。

type PyArray_ArrFuncs

实现内部功能的函数。并非所有这些函数指针都必须为给定类型定义。所需成员包括nonzerocopyswapcopyswapnsetitemgetitemcast。假定这些为非NULL,而NULL条目将导致程序崩溃。其他功能可能为NULL,这只会减少该数据类型的功能。(另外,如果在注册用户定义的数据类型时NULL,则nonzero函数将用默认函数填充)。

typedef  struct  {
  PyArray_VectorUnaryFunc  *cast[NPY_NTYPES];
  PyArray_GetItemFunc  *getitem;
  PyArray_SetItemFunc  *setitem;
  PyArray_CopySwapNFunc  *copyswapn;
  PyArray_CopySwapFunc  *copyswap;
  PyArray_CompareFunc  *compare;
  PyArray_ArgFunc  *argmax;
  PyArray_DotFunc  *dotfunc;
  PyArray_ScanFunc  *scanfunc;
  PyArray_FromStrFunc  *fromstr;
  PyArray_NonzeroFunc  *nonzero;
  PyArray_FillFunc  *fill;
  PyArray_FillWithScalarFunc  *fillwithscalar;
  PyArray_SortFunc  *sort[NPY_NSORTS];
  PyArray_ArgSortFunc  *argsort[NPY_NSORTS];
  PyObject  *castdict;
  PyArray_ScalarKindFunc  *scalarkind;
  int  **cancastscalarkindto;
  int  *cancastto;
  PyArray_FastClipFunc  *fastclip;  /* deprecated */
  PyArray_FastPutmaskFunc  *fastputmask;  /* deprecated */
  PyArray_FastTakeFunc  *fasttake;  /* deprecated */
  PyArray_ArgFunc  *argmin;
}  PyArray_ArrFuncs; 

在描述函数指针时使用了行为良好的段的概念。 行为良好的段是指与数据类型的本机机器字节顺序对齐的段。 nonzerocopyswapcopyswapngetitemsetitem 函数可以(并且必须)处理不规范的数组。 其他函数需要行为良好的内存段。

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

用于将当前类型转换为所有其他内置类型的函数指针数组。 每个函数将由 from 指向的连续、对齐且未交换的缓冲区转换为由 to 指向的连续、对齐且未交换的缓冲区。 要转换的项目数由 n 给出,并且参数 fromarrtoarr 被解释为灵活数组的 PyArrayObjects 以获取 itemsize 信息。

*getitem(void *data, void *arr)

指向从由 data 指向的数组对象 arr 的单个元素返回标准 Python 对象的函数的指针。 该函数必须能够正确处理“不规范”(未对齐和/或已交换)的数组。

int setitem( *item, void *data, void *arr)

指向将 Python 对象 item 设置到数组 arr 中由 data 指向位置的函数的指针。 该函数处理“不规范”的数组。 如果成功,则返回零,否则返回负一(并设置 Python 错误)。

void copyswapn(void *dest, dstride, void *src, sstride, n, int swap, void *arr)
void copyswap(void *dest, void *src, int swap, void *arr)

这些成员都是指向从 src 复制数据到 dest 并在需要时交换的函数的指针。 arr 的值仅用于灵活(NPY_STRINGNPY_UNICODENPY_VOID)数组(并从 arr->descr->elsize 获取)。 第二个函数复制单个值,而第一个函数则使用提供的步幅循环 n 个值。 这些函数可以处理不规范的 src 数据。 如果 src 为 NULL,则不执行复制。 如果 swap 为 0,则不进行字节交换。 假定 destsrc 不重叠。 如果它们重叠,则首先使用 memmove(…)后跟 NULL 值的 src 进行 copyswap(n)

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

指向比较数组 arr 中由 d1d2 指向的两个元素的函数的指针。 此函数需要行为良好的(对齐且未交换)数组。 如果 * d1 > * d2,则返回值为 1,如果 * d1 == * d2,则返回值为 0,如果 * d1 < * d2,则返回值为 -1。 用于灵活数组的数组对象 arr 用于检索 itemsize 和字段信息。

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

指向从由 data 指向的数组中从指向的元素开始的 n 个元素中检索最大索引的函数的指针。 此函数要求内存段是连续且行为良好的。 返回值始终为 0。 最大元素的索引在 max_ind 中返回。

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

指向函数的指针,将两个n长度序列相乘,相加,并将结果放置在arrop指向的元素中。两个序列的起始点由ip1ip2指向。要进入每个序列的下一个元素,分别需要跳过is1is2 字节。此函数需要良好行为的内存(尽管不一定是连续的)。

int scanfunc(FILE *fd, void *ip, void *arr)

指向函数的指针,从文件描述符fd中扫描(类似于 scanf)相应类型的一个元素到由ip指向的数组内存中。假定数组良好行为。最后一个参数arr是要扫描到的数组。返回成功分配的接收参数的数量(如果在分配第一个接收参数之前发生匹配失败,则可能为零),或者如果在分配第一个接收参数之前发生输入失败则返回 EOF。此函数应在不持有 Python GIL 的情况下调用,并且在报告错误时必须抓取它。

int fromstr(char *str, void *ip, char **endptr, void *arr)

指向函数的指针,将由str指向的字符串转换为相应类型的一个元素,并将其放置在由ip指向的内存位置。转换完成后,*endptr指向字符串的剩余部分。最后一个参数arrip指向的数组(对于可变大小数据类型需要)。成功返回 0,失败返回-1。需要一个良好行为的数组。此函数应在不持有 Python GIL 的情况下调用,并且在报告错误时必须抓取它。

nonzero(void *data, void *arr)

指向函数的指针,如果data指向的arr的项非零,则返回 TRUE。该函数可处理不良行为的数组。

void fill(void *data, length, void *arr)

指向函数的指针,用于将给定长度的连续数组填充到数据中。数组的前两个元素必须已经填充。从这两个值中,将计算一个增量,然后通过重复添加此计算出的增量来计算从第 3 个项目到末尾的值。数据缓冲区必须良好行为。

void fillwithscalar(void *buffer, length, void *value, void *arr)

指向函数的指针,用给定的value填充给定length的连续buffer。最后一个参数是需要获取变长数组的项大小。

int sort(void *start, length, void *arr)

一组函数指针的数组,指向特定的排序算法。使用键(到目前为止已定义NPY_QUICKSORTNPY_HEAPSORTNPY_MERGESORT)获得特定的排序算法。这些排序是就地完成的,假设数据是连续且对齐的。

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

一组函数指针的数组,用于这种数据类型的排序算法。与 sort 相同的排序算法可用。产生排序的索引将返回到result(必须初始化为 0 到length-1的索引)。

*castdict

可以为NULL,也可以是包含用户定义数据类型的低级转换函数的字典。每个函数都包装在PyCapsule*中,并以数据类型编号为键。

scalarkind( *arr)

一个确定此类型标量应该如何解释的函数。该参数为NULL或包含数据的零维数组(如果需要确定标量的类型)。返回值必须为类型NPY_SCALARKIND

int **cancastscalarkindto

可以为NULL,也可以是NPY_NSCALARKINDS指针数组。这些指针可以是NULL,也可以是指向整数数组的指针(以NPY_NOTYPE结尾),指示此指定类型的标量可以安全转换的数据类型(通常意味着不会失去精度)。

int *cancastto

可以为NULL,也可以是一个整数数组(以NPY_NOTYPE结尾),指示此数据类型可以安全转换的数据类型(通常意味着不会失去精度)。

void fastclip(void *in, n_in, void *min, void *max, void *out)

自 1.17 版本起已弃用:当np.clip时,使用此函数会引发弃用警告。而不是使用此函数,数据类型必须使用PyUFunc_RegisterLoopForDescr将自定义循环附加到np.core.umath.clipnp.minimumnp.maximum

自 1.19 版本起已弃用:设置此函数已被弃用,应该始终为NULL,如果设置了,将被忽略。

一个从in中读取n_in个项目,并在minmax指向的限制内写入out的值的函数,如果读取的值在minmax指向的限制内,或者在外部,则相应的限制。内存段必须是连续的且表现良好,minmax可以为NULL,但不能同时为NULL

void fastputmask(void *in, void *mask, n_in, void *values, nv)

自 1.19 版本起已弃用:设置此函数已被弃用,应该始终为NULL,如果设置了,将被忽略。

一个使用指针in指向一个包含n_in个项目的数组,指针mask指向一个包含n_in个布尔值的数组,以及指针vals指向一个包含nv个项目的数组的函数。将vals中的项目复制到in中,无论mask中的值是否为非零,在nv < n_in的情况下需要按需平铺vals。所有数组必须是连续的且表现良好。

void fasttake(void *dest, void *src, *indarray, nindarray, n_outer, m_middle, nelem, clipmode)

自 1.19 版本起已弃用:设置此函数已被弃用,应该始终为NULL,如果设置了,将被忽略。

一个函数,它接受指向 C 连续、行为良好段的指针src,解释为形状为(n_outer, nindarray, nelem)的 3 维数组,指向indarray指针到m_middle整数索引的连续、行为良好段,以及指向 C 连续、行为良好段的指针dest,解释为形状为(n_outer, m_middle, nelem)的 3 维数组。indarray中的索引用于沿第二维索引src,并将nelem项的相应块复制到destclipmode(可以取值NPY_RAISENPY_WRAPNPY_CLIP)确定小于 0 或大于nindarray的索引将如何处理。

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

指针指向一个函数,该函数检索数组arr中从指向data的元素开始的n个元素中最小的索引。此函数要求内存段是连续且行为良好。返回值始终为 0。最小元素的索引在min_ind中返回。

PyArray_Type类型对象实现了许多Python 对象的特性,包括tp_as_numbertp_as_sequencetp_as_mappingtp_as_buffer接口。还使用了rich comparison以及成员(tp_members)和属性(tp_getset)的新式属性查找。PyArray_Type也可以被子类化。

提示

tp_as_number 方法使用通用方法调用已注册用于处理操作的函数。当导入_multiarray_umath模块时,它将所有数组的数字操作设置为相应的 ufunc。可以使用PyUFunc_ReplaceLoopBySignature更改此选择,也可以使用PyArray_SetStringFunction改变tp_strtp_repr方法。

PyUFunc_Type 和 PyUFuncObject

PyUFunc_Type

ufunc 对象是通过创建PyUFunc_Type来实现的。这是一种非常简单的类型,仅实现了基本的 getattribute 行为、打印行为,并具有调用行为,允许这些对象像函数一样运行。ufunc 的基本思想是持有对支持该操作的每种数据类型的快速 1 维(向量)循环的引用。这些一维循环都具有相同的签名,并且是创建新 ufunc 的关键。它们由通用循环代码在适当的时候调用,以实现 N 维函数。还为浮点和复数浮点数组定义了一些通用的 1-d 循环,允许您使用单个标量函数定义 ufunc(例如atanh)。

type PyUFuncObject

ufunc 的核心是PyUFuncObject,它包含调用执行实际工作的基础 C 代码循环所需的所有信息。虽然这里描述了完整的内容,但它应被视为 NumPy 的内部内容,并通过PyUFunc_*函数来操作。该结构的大小可能会因 NumPy 的不同版本而发生变化。为了确保兼容性:

  • 永远不要声明结构的非指针实例

  • 永远不要执行指针算术

  • 永远不要使用sizeof(PyUFuncObject)

它具有以下结构:

typedef  struct  {
  PyObject_HEAD
  int  nin;
  int  nout;
  int  nargs;
  int  identity;
  PyUFuncGenericFunction  *functions;
  void  **data;
  int  ntypes;
  int  reserved1;
  const  char  *name;
  char  *types;
  const  char  *doc;
  void  *ptr;
  PyObject  *obj;
  PyObject  *userloops;
  int  core_enabled;
  int  core_num_dim_ix;
  int  *core_num_dims;
  int  *core_dim_ixs;
  int  *core_offsets;
  char  *core_signature;
  PyUFunc_TypeResolutionFunc  *type_resolver;
  PyUFunc_LegacyInnerLoopSelectionFunc  *legacy_inner_loop_selector;
  void  *reserved2;
  npy_uint32  *op_flags;
  npy_uint32  *iter_flags;
  /* new in API version 0x0000000D */
  npy_intp  *core_dim_sizes;
  npy_uint32  *core_dim_flags;
  PyObject  *identity_value;
  /* Further private slots (size depends on the NumPy version) */
}  PyUFuncObject; 
int nin

输入参数的数量。

int nout

输出参数的数量。

int nargs

参数的总数(nin + nout)。这必须小于NPY_MAXARGS

int identity

要么PyUFunc_OnePyUFunc_ZeroPyUFunc_MinusOnePyUFunc_NonePyUFunc_ReorderableNonePyUFunc_IdentityValue用于指示该操作的身份。它仅在对空数组进行类似于 reduce 的调用时使用。

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

一个函数指针数组—每种 ufunc 支持的数据类型都有一个。这是被调用以实现底层函数的向量循环,dims [0]次。第一个参数args是一个包含nargs指针的行为内存数组。首先是输入参数的数据指针,然后是输出参数的数据指针。必须跳过多少字节才能到达序列中的下一个元素是由steps数组中的相应条目指定的。最后一个参数允许循环接收额外的信息。这通常用于一个通用的向量循环可以用于多个函数的情况。在这种情况下,要调用的实际标量函数作为extradata传递进来。该函数指针数组的大小为 ntypes。

void **data

要传递给 1-d 向量循环的额外数据,如果不需要额外数据则为 NULL。这个 C 数组必须与函数数组的大小相同( ntypes)。如果不需要额外数据,则使用 NULL。对于 UFuncs 的几个 C-API 调用只是使用这些额外数据的 1-d 向量循环,以接收指向要调用的实际函数的指针。

int ntypes

ufunc 支持的数据类型数量。这个数字指定了内置数据类型的多少不同的 1-d 循环可用。

int reserved1

未使用。

char *name

ufunc 的字符串名称。这在动态构建 ufuncs 的 __doc__ 属性时使用。

char *types

一个 (nargs \times ntypes) 的 8 位 type_numbers 数组,其中包含函数对于每个支持的(内置)数据类型的类型签名。对于每个 ntypes 函数,该数组中相应的类型编号集显示了 1-d 向量循环中 args 参数应该如何解释。这些类型编号不必是相同的类型,支持混合类型的 ufuncs。

char *doc

ufunc 的文档。不应该包含函数签名,因为在检索 __doc__ 时会动态生成。

void *ptr

任何动态分配的内存。目前,这用于从 Python 函数创建动态 ufuncs,用于存储类型、数据和名称成员的空间。

*obj

对于从 Python 函数动态创建的 ufuncs,这个成员保存对底层 Python 函数的引用。

*userloops

用户定义的 1-d 向量循环的字典(存储为 CObject ptrs)用于用户定义的类型。用户可以为任何用户定义的类型注册一个循环。它通过类型编号检索。用户定义的类型编号始终大于NPY_USERDEF

int core_enabled

标量 ufunc 为 0;广义 ufunc 为 1

int core_num_dim_ix

签名中核心维度名称的不同个数

int *core_num_dims

每个参数的核心维度的数量

int *core_dim_ixs

以扁平化的形式存储的维度索引;第 k 个参数的索引存储在 core_dim_ixs[core_offsets[k] : core_offsets[k] + core_numdims[k]]

int *core_offsets

每个参数中第一个核心维度的位置在 core_dim_ixs 中,等同于累加和(core_num_dims)

char *core_signature

核心签名字符串

PyUFunc_TypeResolutionFunc *type_resolver

解析类型并填充输入和输出的 dtypes 的函数

PyUFunc_LegacyInnerLoopSelectionFunc *legacy_inner_loop_selector

从版本 1.22 起弃用:这个插槽存在某些后备支持,但最终将被移除。依赖于此的通用函数最终将必须迁移。参见NEP 41NEP 43

void *reserved2

用于可能的将来使用具有不同签名的循环选择器。

op_flags

重写每个 ufunc 操作数的默认操作数标志。

iter_flags

重写 ufunc 的默认 nditer 标志。

在 API 版本 0x0000000D 中添加

*core_dim_sizes

对于每个不同的核心尺寸,如果UFUNC_CORE_DIM_SIZE_INFERRED 等于 0,则是 p签名的可能大小

*core_dim_flags

每个不同的核心维度,一组标志(UFUNC_CORE_DIM_CAN_IGNOREUFUNC_CORE_DIM_SIZE_INFERRED

*identity_value

缩减的身份,当PyUFuncObject.identity 等于PyUFunc_IdentityValue时。

UFUNC_CORE_DIM_CAN_IGNORE

如果维度名称以 ? 结尾

UFUNC_CORE_DIM_SIZE_INFERRED

若维度大小将由操作数确定,并非来自 frozen 签名

PyArrayIter_Type 和 PyArrayIterObject

PyArrayIter_Type

这是一个迭代器对象,它可以轻松地循环访问 N 维数组。 这是从 ndarray 的 flat 属性返回的对象。 它还广泛用于整体实现内部,用于循环访问 N 维数组。 interface 已实现,使得可以对迭代器对象进行索引(使用 1-d 索引),并且一些方法通过tp_methods表进行了实现。 此对象实现了next方法,并且可以在 Python 中使用任何可以使用迭代器的地方。

type PyArrayIterObject

PyArrayIter_Type对象对应的 C-结构是PyArrayIterObject. PyArrayIterObject 用于跟踪指向 N 维数组的指针。 它包含相关信息,用于快速遍历数组。 指针可以通过三种基本方法进行调整:1) 以 C 风格连续的方式前进到数组中的“下一个”位置,2) 前进到数组中的任意 N 维坐标,和 3) 前进到数组中的任意一维索引。 这些计算中使用了PyArrayIterObject结构的成员。 迭代器对象保留其数组的维度和步幅信息。这可以根据需要进行“广播”,或者仅循环特定维度。

typedef  struct  {
  PyObject_HEAD
  int  nd_m1;
  npy_intp  index;
  npy_intp  size;
  npy_intp  coordinates[NPY_MAXDIMS];
  npy_intp  dims_m1[NPY_MAXDIMS];
  npy_intp  strides[NPY_MAXDIMS];
  npy_intp  backstrides[NPY_MAXDIMS];
  npy_intp  factors[NPY_MAXDIMS];
  PyArrayObject  *ao;
  char  *dataptr;
  npy_bool  contiguous;
}  PyArrayIterObject; 
int nd_m1

(N-1) 其中 (N) 是底层数组中的维数。

index

当前数组的 1-d 索引。

size

底层数组的总大小。

*coordinates

一个 (N) -维数组的索引。

*dims_m1

每个维度中数组的大小减 1。

*strides

数组的步幅。在每个维度中,跳到下一个元素需要多少字节。

*backstrides

从维度末尾跳回到其开头需要多少字节。注意 backstrides[k] == strides[k] * dims_m1[k],但它存储在这里是一种优化。

*factors

此数组用于计算从 1-d 索引到 N-d 索引的所需乘积。

*ao

创建此迭代器表示的基础 ndarray 的指针。

char *dataptr

此成员指向由索引指示的 ndarray 中的元素。

contiguous

如果底层数组为NPY_ARRAY_C_CONTIGUOUS,则此标志为真。它用于尽可能简化计算。

如何在 C 级别上使用数组迭代器在后续部分中有更详细的解释。通常情况下,您无需关注迭代器对象的内部结构,而只需通过宏 PyArray_ITER_NEXT (it)、PyArray_ITER_GOTO (it, dest) 或 PyArray_ITER_GOTO1D (it, index) 与之交互即可。所有这些宏都要求参数 it 是一个 PyArrayIterObject*。

PyArrayMultiIter_TypePyArrayMultiIterObject

PyArrayMultiIter_Type

这种类型提供了一种封装了广播概念的迭代器。它允许将 (N) 个数组一起广播,以便循环按照 C 风格的连续方式在广播的数组上进行。相应的 C 结构是 PyArrayMultiIterObject,其内存布局必须从传递给 PyArray_Broadcast (obj) 函数的任何对象 obj 开始。通过调整数组迭代器来执行广播,使得每个迭代器表示广播的形状和大小,但其步幅被调整,以便在每次迭代中使用数组中的正确元素。

type PyArrayMultiIterObject
typedef  struct  {
  PyObject_HEAD
  int  numiter;
  npy_intp  size;
  npy_intp  index;
  int  nd;
  npy_intp  dimensions[NPY_MAXDIMS];
  PyArrayIterObject  *iters[NPY_MAXDIMS];
}  PyArrayMultiIterObject; 
int numiter

需要广播到相同形状的数组数量。

size

广播的总大小。

index

广播结果中当前的(1-d)索引。

int nd

广播结果中的维数数量。

*dimensions

广播结果的形状(仅使用 nd 个槽)。

**iters

一个包含为一起广播的数组调整过迭代器的迭代器对象数组。返回时,这些迭代器已调整好以进行广播。

PyArrayNeighborhoodIter_TypePyArrayNeighborhoodIterObject

PyArrayNeighborhoodIter_Type

这是一个迭代器对象,使得在 N 维邻域上循环变得��易。

type PyArrayNeighborhoodIterObject

与对象 PyArrayNeighborhoodIter_Type 对应的 C 结构是 PyArrayNeighborhoodIterObject

typedef  struct  {
  PyObject_HEAD
  int  nd_m1;
  npy_intp  index,  size;
  npy_intp  coordinates[NPY_MAXDIMS]
  npy_intp  dims_m1[NPY_MAXDIMS];
  npy_intp  strides[NPY_MAXDIMS];
  npy_intp  backstrides[NPY_MAXDIMS];
  npy_intp  factors[NPY_MAXDIMS];
  PyArrayObject  *ao;
  char  *dataptr;
  npy_bool  contiguous;
  npy_intp  bounds[NPY_MAXDIMS][2];
  npy_intp  limits[NPY_MAXDIMS][2];
  npy_intp  limits_sizes[NPY_MAXDIMS];
  npy_iter_get_dataptr_t  translate;
  npy_intp  nd;
  npy_intp  dimensions[NPY_MAXDIMS];
  PyArrayIterObject*  _internal_iter;
  char*  constant;
  int  mode;
}  PyArrayNeighborhoodIterObject; 

PyArrayFlags_TypePyArrayFlagsObject

PyArrayFlags_Type

当从 Python 检索 flags 属性时,将构造这种特殊的内置对象。这种特殊类型通过将其作为属性访问这些不同的标志,或者通过将其作为字典访问,其中标志名称作为条目,使得更容易处理不同的标志。

type PyArrayFlagsObject
typedef  struct  PyArrayFlagsObject  {
  PyObject_HEAD
  PyObject  *arr;
  int  flags;
}  PyArrayFlagsObject; 

ScalarArrayTypes

对于数组中可能存在的不同内置数据类型,每个都有一个 Python 类型。其中大部分只是对应的 C 中数据类型的简单包装。这些类型的 C 名称为Py{TYPE}ArrType_Type,其中{TYPE}可以是

BoolByteShortIntLongLongLongUByteUShortUIntULongULongLongHalfFloatDoubleLongDoubleCFloatCDoubleCLongDoubleStringUnicodeVoid,和Object

这些类型名称是 C-API 的一部分,因此可以在扩展 C 代码中创建它们。还有一个PyIntpArrType_Type和一个PyUIntpArrType_Type,它们可以简单地替代可以在平台上保存指针的整数类型之一。这些标量对象的结构不暴露给 C 代码。函数PyArray_ScalarAsCtype(..)可用于从数组标量中提取 C 类型值,而函数PyArray_Scalar(...)可用于从 C 值构造数组标量。

其他 C 结构

发现在 NumPy 开发中几个新的 C 结构非常有用。这些 C 结构至少在一个 C-API 调用中被使用,因此在此进行了文档化。定义这些结构的主要原因是为了简化使用 Python ParseTuple C-API,将 Python 对象转换为有用的 C 对象。

PyArray_Dims

type PyArray_Dims

当需要解释形状和/或步幅信息时,此结构非常有用。该结构是:

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

该结构的成员有

*ptr

指向(npy_intp)整数列表的指针,通常表示数组形状或数组步幅。

int len

整数列表的长度。假定可以安全地访问ptr[0]至ptr[len-1]。

PyArray_Chunk

type PyArray_Chunk

这相当于 Python 中缓冲区对象结构,直到 ptr 成员。在 32 位平台上(即如果NPY_SIZEOF_INT == NPY_SIZEOF_INTP),len 成员也与缓冲区对象的等效成员匹配。用于表示通用单段内存块。

typedef  struct  {
  PyObject_HEAD
  PyObject  *base;
  void  *ptr;
  npy_intp  len;
  int  flags;
}  PyArray_Chunk; 

其成员有

*base

此内存块来自的 Python 对象。需要这样做以正确计算内存。

void *ptr

指向内存单段块的起始位置的指针。

len

段的长度(以字节为单位)。

int flags

任何应该用于解释内存的数据标志(例如NPY_ARRAY_WRITEABLE)。

PyArrayInterface

另请参阅

数组接口协议

type PyArrayInterface

PyArrayInterface 结构定义了 NumPy 和其他扩展模块可以使用的快速数组接口协议。支持快速数组接口协议的对象的 __array_struct__ 方法应返回一个包含指向 PyArrayInterface 结构的指针的 PyCapsule,其中包含数组的相关详细信息。创建新数组后,应DECREF该属性,这将释放 PyArrayInterface 结构的内存。记得INCREF获取 __array_struct__ 属性的对象,并将新 PyArrayObject 的 base 成员指向同一对象。通过这种方式,数组的内存将正确管理。

typedef  struct  {
  int  two;
  int  nd;
  char  typekind;
  int  itemsize;
  int  flags;
  npy_intp  *shape;
  npy_intp  *strides;
  void  *data;
  PyObject  *descr;
}  PyArrayInterface; 
int two

作为健全性检查的整数 2。

int nd

数组中的维度数。

char typekind

根据类型字符串约定指示存在什么类型的数组的字符,将 ‘t’ -> 位域,‘b’ -> 布尔值,‘i’ -> 有符号整数,‘u’ -> 无符号整数,‘f’ -> 浮点,‘c’ -> 复数浮点,‘O’ -> 对象,‘S’ -> (字节)字符串,‘U’ -> Unicode,‘V’ -> void。

int itemsize

数组中每个项所需的字节数。

int flags

任何一个位 NPY_ARRAY_C_CONTIGUOUS (1),NPY_ARRAY_F_CONTIGUOUS (2),NPY_ARRAY_ALIGNED (0x100),NPY_ARRAY_NOTSWAPPED (0x200),或 NPY_ARRAY_WRITEABLE (0x400),以指示有关数据的一些信息。实际上,可以从其他参数确定标志 NPY_ARRAY_ALIGNEDNPY_ARRAY_C_CONTIGUOUSNPY_ARRAY_F_CONTIGUOUS。标志 NPY_ARR_HAS_DESCR (0x800) 也可以设置,以向消费版本 3 数组接口的对象指示结构的 descr 成员存在(版本 2 的数组接口将忽略它)。

*shape

包含数组每个维度的大小的数组。

*strides

包含在每个维度中跳过下一个元素所需的字节数的数组。

void *data

指向数组第一个元素的指针。

*descr

描述数据类型详细信息的 Python 对象(与__array_interface__中的descr键相同)。如果typekinditemsize提供足够的信息,这个字段可以为NULL。除非在flags中打开了NPY_ARR_HAS_DESCR标志,否则此字段也会被忽略。

内部使用的结构

内部,该代码使用了一些额外的 Python 对象,主要用于内存管理。这些类型无法直接从 Python 访问,并且不会暴露给 C-API。它们在此处仅用于完整性和帮助理解代码。

type PyUFunc_Loop1d

简单的 C 结构链表,包含了为用户定义的数据类型的每个定义的签名定义 1-d 循环所需的信息。

PyArrayMapIter_Type

使用此 Python 类型处理高级索引。它只是一个松散的包装器,包装了包含高级数组索引所需变量的 C 结构。

type PyArrayMapIterObject

PyArrayMapIter_Type相关联的 C 结构。如果你正在尝试理解高级索引映射代码,这个结构很有用。它在arrayobject.h头文件中定义。此类型未暴露给 Python,可以用 C 结构替换。作为 Python 类型,它利用引用计数内存管理。

PyArray_Dims

type PyArray_Dims

当形状和/或步长信息需要被解释时,这个结构非常有用。结构是:

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

这个结构的成员是

*ptr

指向一个(npy_intp)整数列表的指针,通常表示数组的形状或数组的步长。

int len

整数列表的长度。假定可以安全访问ptr[0]到ptr[len-1]。

PyArray_Chunk

type PyArray_Chunk

这与 Python 中的缓冲对象结构相当,直到 ptr 成员。在 32 位平台上( if NPY_SIZEOF_INT == NPY_SIZEOF_INTP),len 成员也与缓冲对象的等效成员匹配。它用于表示通用单段内存块。

typedef  struct  {
  PyObject_HEAD
  PyObject  *base;
  void  *ptr;
  npy_intp  len;
  int  flags;
}  PyArray_Chunk; 

这些成员是

*base

分配这块内存的 Python 对象。需要这样以便能够正确计算内存使用。

void *ptr

指向单个内存块的起始指针。

len

段的字节长度。

int flags

用于解释内存的任何数据标志(例如 NPY_ARRAY_WRITEABLE)。

PyArrayInterface

另请参见

数组接口协议

type PyArrayInterface

PyArrayInterface结构被定义为 NumPy 和其他扩展模块可以使用快速数组接口协议。支持快速数组接口协议的对象的__array_struct__方法应返回包含指向具有数组的相关细节的PyArrayInterface结构的指针的PyCapsule。创建新数组后,应DECREF该属性,这将释放PyArrayInterface结构。记得INCREF这个对象(其__array_struct__属性已被检索)并将新PyArrayObject的 base 成员指向同一对象。这样数组的内存将得到正确管理。

typedef  struct  {
  int  two;
  int  nd;
  char  typekind;
  int  itemsize;
  int  flags;
  npy_intp  *shape;
  npy_intp  *strides;
  void  *data;
  PyObject  *descr;
}  PyArrayInterface; 
int two

整数2作为健全性检查。

int nd

数组中的维度数。

char typekind

根据类型字符串约定指示出现的数组类型的字符,‘t’ -> 位字段,‘b’ -> 布尔,‘i’ -> 有符号整数,‘u’ -> 无符号整数,‘f’ -> 浮点数,‘c’ -> 复数浮点数,‘O’ -> 对象,‘S’ -> (字节)字符串,‘U’ -> Unicode,‘V’ -> 空。

int itemsize

数组中每个项所需的字节数。

int flags

位之一NPY_ARRAY_C_CONTIGUOUS(1)、NPY_ARRAY_F_CONTIGUOUS(2)、NPY_ARRAY_ALIGNED(0x100)、NPY_ARRAY_NOTSWAPPED(0x200)或NPY_ARRAY_WRITEABLE(0x400)用于指示数据的某些内容。NPY_ARRAY_ALIGNEDNPY_ARRAY_C_CONTIGUOUSNPY_ARRAY_F_CONTIGUOUS标志实际上可以从其他参数中确定。标志NPY_ARR_HAS_DESCR(0x800)也可以设置为指示消耗版本 3 数组接口的对象,结构的 descr 成员存在(对于消耗版本 2 的数组接口的对象将被忽略)。

*shape

包含每个维度中数组大小的数组。

*strides

包含跳转到每个维度中下一个元素所需字节数的数组。

void *data

指向数组第一个元素的指针。

*descr

描述数据类型的 Python 对象更详细(与__array_interface__中的descr键相同)。如果typekinditemsize提供足够信息,则此字段可以是NULL。除非flags中打开了NPY_ARR_HAS_DESCR标志,否则此字段也会被忽略。

内部使用的结构

在内部,代码主要用于内存管理的一些额外的 Python 对象。这些类型不能直接从 Python 访问,也未暴露给 C-API。它们仅在此列出,以完整和帮助理解代码。

type PyUFunc_Loop1d

包含定义用户定义数据类型的每个签名的 1-d 循环所需信息的 C 结构的简单链接列表。

PyArrayMapIter_Type

高级索引使用这种 Python 类型处理。它只是围绕包含高级数组索引所需变量的 C 结构的松散包装。

type PyArrayMapIterObject

PyArrayMapIter_Type相关联的 C 结构。如果您试图理解高级索引映射代码,这个结构非常有用。它在arrayobject.h头文件中定义。这种类型并未暴露给 Python,可以用 C 结构替代。作为 Python 类型,它利用引用计数的内存管理。

posted @ 2024-06-24 14:55  绝不原创的飞龙  阅读(2)  评论(0编辑  收藏  举报