Python:类型和数据类型之间的混淆
假设我进入:Python:类型和数据类型之间的混淆,python,numpy,types,unsigned-integer,Python,Numpy,Types,Unsigned Integer,假设我进入: a = uint8(200) a*2 然后结果是400,它被重铸为uint16类型 然而: a = array([200],dtype=uint8) a*2 结果是 array([144], dtype=uint8) 乘法以256模执行,以确保结果保留在一个字节内 我对“类型”和“数据类型”以及其中一种类型优先于另一种类型感到困惑。正如您所看到的,类型可能会对输出产生显著的影响 例如,我是否可以创建一个数据类型uint8,以便对该数字执行256模运算?或者,我可以创建一个ui
a = uint8(200)
a*2
然后结果是400,它被重铸为uint16类型
然而:
a = array([200],dtype=uint8)
a*2
结果是
array([144], dtype=uint8)
乘法以256模执行,以确保结果保留在一个字节内
我对“类型”和“数据类型”以及其中一种类型优先于另一种类型感到困惑。正如您所看到的,类型可能会对输出产生显著的影响
例如,我是否可以创建一个数据类型uint8,以便对该数字执行256模运算?或者,我可以创建一个uint8类型(不是dtype)的数组,这样对它的操作将产生0-255范围以外的值吗?一个numpy数组包含相同类型的元素,因此
np。数组([200],dtype=uint8)
是一个具有一个uint8类型值的数组。如果执行np.uint8(200)
,则没有数组,只有一个值。这将产生巨大的不同
在数组上执行某些操作时,无论单个值是否溢出,类型都保持不变。禁止在阵列中自动向上投射,因为整个阵列的大小必须改变。只有当用户明确希望这样做时,才会这样做。当对单个值执行操作时,它可以很容易地向上转换,而不会影响其他值。NumPy数组的类型是NumPy.ndarray
;这就是Python对象的类型(类似于type(“hello”)
就是str
)
dtype
只定义了如何用标量(即单个数字)或数组解释内存中的字节,以及处理字节的方式(例如int
/float
)。因此,您不会更改数组或标量的type
,只更改其dtype
正如您所观察到的,如果将两个标量相乘,则生成的数据类型是两个值都可以转换到的最小“安全”类型。但是,将数组与标量相乘只会返回相同数据类型的数组。函数np.inspect\u types
的属性可以清楚地了解特定标量或数组对象的dtype
何时更改:
NumPy的P>类型推广与C++语言中的规则相似,但也有一些细微的差别。同时使用标量和数组时,数组的类型优先,并考虑标量的实际值
文件继续:
如果只有标量或标量的最大类别高于数组的最大类别,则数据类型将与promote\u types
组合以生成返回值
因此,对于np.uint8(200)*2
,两个标量,得到的数据类型将是以下返回的类型:
对于np.array([200],dtype=np.uint8)*2
数组的数据类型优先于标量int
,并返回np.uint8
数据类型
要解决关于在操作期间保留标量的dtype
的最后一个问题,您必须限制您使用的任何其他标量的数据类型,以避免NumPy的自动dtype
升级:
>>> np.array([200], dtype=np.uint8) * np.uint8(2)
144
当然,另一种选择是简单地将单个值包装在NumPy数组中(这样NumPy就不会在使用不同的dtype
标量的操作中强制转换它)
要在操作期间提升数组的类型,可以先在数组中包装任何标量:
>>> np.array([200], dtype=np.uint8) * np.array([2])
array([400])
简单而高级的答案是,NumPy在Python的类型系统之上分层了第二个类型系统
当您询问NumPy对象的类型时,您会得到容器的类型——类似于NumPy.ndarray
。但是当您请求dtype
时,您得到的是元素的(numpy-managed)类型
在其他情况下,没有等效的Python类型。例如,当您指定uint8
时。这样的数据值/类型可以由Python管理,但与C、Rust和其他“系统语言”不同,管理直接与机器数据类型对齐的值(如uint8
与“无符号字节”计算紧密对齐)不是Python的常见用例
所以最大的问题是NumPy提供了数组和矩阵之类的容器,它们在自己的类型系统下运行。它还提供了一系列非常有用、优化良好的例程来操作这些容器(及其元素)。如果使用care,您可以混合和匹配numpython和普通Python计算
没有Python类型uint8
。有一个名为uint8
的构造函数,调用该构造函数时返回NumPy类型:
>>> u = uint8(44)
>>> u
44
>>> u.dtype
dtype('uint8')
>>> type(u)
<type 'numpy.uint8'>
但如果您想计算mod 256的值,那么使用Python的mod运算符可能更容易:
>> (44 + 1000) % 256
20
将大于255的数据值驱动到uint8
数据类型中,然后执行算术是获得mod-256算术的一种相当隐蔽的方法。如果您不小心,您可能会导致Python将您的值“升级”为全整数(杀死您的mod-256方案),或者触发溢出异常(因为在C和机器语言中工作良好的技巧通常会被更高级的语言标记)。“dtype
只定义了内存中的字节如何被标量解释。”→ 它还定义了它们的解释方式(例如,int32
vsfloat32
)。
>>> arr.dtype == float
True
>>> arr.dtype is float
False
>>> u = uint8(44)
>>> u
44
>>> u.dtype
dtype('uint8')
>>> type(u)
<type 'numpy.uint8'>
>>> uint8(44 + 1000)
20
>>> uint8(44) + uint8(1000)
20
>> (44 + 1000) % 256
20