Python:类型和dtypes之间的混淆

时间:2015-01-05 13:46:34

标签: python numpy types unsigned-integer

假设我输入:

a = uint8(200)
a*2

然后结果是400,并且重铸为uint16类型。

然而:

a = array([200],dtype=uint8)
a*2

,结果是

array([144], dtype=uint8)

乘法以256为模进行,以确保结果保持在一个字节中。

我对"类型"感到困惑。和" dtypes"并且使用一个而不是另一个。如您所见,类型可能会对输出产生显着影响。

例如,我可以创建单个数量的dtype uint8,以便对该数字的操作将以256为模进行吗?或者,我可以创建一个类型(不是dtype)uint8的数组,以便对它的操作产生超出0-255范围的值吗?

3 个答案:

答案 0 :(得分:9)

NumPy数组的typenumpy.ndarray;这只是Python对象的类型(类似于type("hello") str的例子)。

dtype只定义内存中的字节将如何由标量(即单个数字)或数组解释,以及字节的处理方式(例如int / {{1 }})。因此,您不会更改数组或标量的float,只更改其type

如您所见,如果将两个标量相乘,则生成的数据类型是可以转换这两个值的最小“安全”类型。但是,将数组和标量相乘只会返回相同数据类型的数组。函数dtype的{​​{3}}清楚地表明特定标量或数组对象的np.inspect_types何时发生变化:

  

NumPy中的类型提升与C ++等语言中的规则类似,但略有不同。当使用标量和数组时,数组的类型优先,并考虑标量的实际值。

文档仍在继续:

  

如果只有标量或标量的最大类别高于数组的最大类别,则数据类型与dtype组合以产生返回值。

因此对于promote_types两个标量,生成的数据类型将是documentation返回的类型:

np.uint8(200) * 2

对于>>> np.promote_types(np.uint8, int) dtype('int32') ,数组的数据类型优先于标量np.array([200], dtype=np.uint8) * 2,并返回int数据类型。

要解决有关在操作期间保留标量np.uint8的最终问题,您必须限制用于避免NumPy自动dtype促销的任何其他标量的数据类型:

dtype

当然,替代方法是简单地将单个值包装在NumPy数组中(然后NumPy不会在使用不同>>> np.array([200], dtype=np.uint8) * np.uint8(2) 144 的标量的操作中将其强制转换。)

要在操作期间提升数组的类型,可以先将任何标量包装在数组中:

dtype

答案 1 :(得分:6)

简单,高级的答案是NumPy在Python的类型系统上层叠第二类系统。

当您要求NumPy对象的type时,您会获得容器的类型 - 类似于numpy.ndarray。但是,当您要求dtype时,您将获得元素的(numpy-managed)类型。

>>> from numpy import *
>>> arr = array([1.0, 4.0, 3.14])
>>> type(arr)
<type 'numpy.ndarray'>
>>> arr.dtype
dtype('float64')

有时,与使用默认float类型时一样,元素数据类型(dtype)等同于Python类型。但这相当于,不相同:

>>> arr.dtype == float
True
>>> arr.dtype is float
False

在其他情况下,没有等效的Python类型。例如,当您指定uint8时。这些数据值/类型可以由Python管理,但与C,Rust和其他系统语言不同,&#34;管理直接与机器数据类型对齐的值(如uint8与&#34;无符号字节&#34;计算)紧密对齐不是Python的常见用例。

因此,重要的是NumPy提供了在其自己的类型系统下运行的数组和矩阵等容器。它提供了一系列非常有用,优化良好的例程来操作这些容器(及其元素)。如果你小心,你可以混合和匹配NumPy和普通的Python计算。

没有Python类型uint8。有一个名为uint8的构造函数,在调用时返回NumPy类型:

>>> u = uint8(44)
>>> u
44
>>> u.dtype
dtype('uint8')
>>> type(u)
<type 'numpy.uint8'>

所以&#34;我可以创建一个类型的数组(不是dtype)uint8 ...?&#34;不,你不能。没有这样的动物。 您可以 在不使用NumPy uint8(a.k.a。NumPy标量值)的情况下,将计算约束为arrays规则。 E.g:

>>> uint8(44 + 1000)
20
>>> uint8(44) + uint8(1000)
20

但是如果你想计算mod 256的值,它可能更容易使用Python的mod运算符:

>> (44 + 1000) % 256
20

将大于255的数据值驱动到uint8数据类型中,然后进行算术运算是获得mod-256算法的一种后门方式。如果你不小心,你可能会导致Python升级&#34;你的值为全整数(杀死你的mod-256方案),或触发溢出异常(因为在C和机器语言中效果很好的技巧通常被更高级别的语言标记)。

答案 2 :(得分:3)

numpy数组包含相同类型的元素,因此np.array([200],dtype=uint8) 是一个数组为uint8的值为的数组。执行np.uint8(200)时,您没有数组,只有单个值。这会产生巨大的差异。

对阵列执行某些操作时,类型保持不变,无论单个值是否溢出。禁止在数组中自动向上转换,因为整个数组的大小必须改变。只有在用户明确需要时才会这样做。对单个值执行操作时,它可以轻松地进行上传,而不会影响其他值。