测试 numpy.dtype 的正确方法

新手上路,请多包涵

我正在查看具有以下 if 测试的第三方库:

 if isinstance(xx_, numpy.ndarray) and xx_.dtype is numpy.float64 and xx_.flags.contiguous:
    xx_[:] = ctypes.cast(xx_.ctypes._as_parameter_,ctypes.POINTER(ctypes.c_double))

似乎 xx_.dtype is numpy.float64 总是失败:

 >>> xx_ = numpy.zeros(8, dtype=numpy.float64)
>>> xx_.dtype is numpy.float64

False

测试 numpy 数组的 dtypefloat64 的正确方法是什么?

原文由 Zero 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 533
2 个回答

这是库中的错误。

dtype 可以动态构造对象。 NumPy 一直都是这样做的。无法保证他们在任何地方都被拘留,因此构建一个已经存在的 dtype 会给你同样的结果。

最重要的是, np.float64 实际上不是 dtype ;这是一个……我不知道这些类型叫什么,但是用于从数组字节构造标量对象的类型,通常在 type 属性中找到 dtype ,所以我将其称为 dtype.type 。 (注意 np.float64 是 NumPy 的数字塔类型和 Python 的数字塔 ABC 的子类,而 np.dtype 当然不是。)

通常,您可以互换使用它们;当您使用 dtype.type — 或者,就此而言,本地 Python 数字类型 — 其中 dtype 是预期的, dtype 同样,不能保证会被拘留),但这当然并不意味着它们是相同的:

 >>> np.float64 == np.dtype(np.float64) == np.dtype('float64')
True
>>> np.float64 == np.dtype(np.float64).type
True

如果您使用内置类型,则 dtype.type 通常 是相同的:

 >>> np.float64 is np.dtype(np.float64).type
True

但是两个 dtype 通常不是:

 >>> np.dtype(np.float64) is np.dtype('float64')
False

但同样,这些都不能保证。 (另外,请注意 np.float64float 使用完全相同的存储,但是是不同的类型。当然你也可以制作一个 dtype('f8') ,保证to work the same as dtype(np.float64) , but that doesn’t mean 'f8' is , or even == , np.float64 .)

因此,有可能通过显式传递 np.float64 作为它的 dtype 参数来构造一个数组,这意味着当你检查 dtype.type 属性时,你会得到相同的实例不能保证。如果你传递 np.dtype('float64') ,或者你要求 NumPy 从数据中推断它,或者你传递一个 dtype 字符串让它像 'f8' 一样解析,等等,它更不可能匹配。更重要的是,您 绝对 不会将 np.float64 返回为 dtype 本身。


那么,应该如何修复呢?

好吧,文档定义了两个 dtype 相等 的含义,这是一个有用的东西,我认为这可能是您在这里寻找的有用的东西。因此,只需将 is 替换为 --- ==

 if isinstance(xx_, numpy.ndarray) and xx_.dtype == numpy.float64 and xx_.flags.contiguous:

但是,在某种程度上,我只是猜测这就是您要找的东西。 (它正在检查连续标志的事实意味着它可能会直接进入内部存储……但为什么它不检查 C 与 Fortran 顺序、字节顺序或其他任何内容?)

原文由 abarnert 发布,翻译遵循 CC BY-SA 3.0 许可协议

尝试:

 x = np.zeros(8, dtype=np.float64)
print x.dtype is np.dtype(np.float64))

is 测试两个对象的身份,它们是否相同 id() 。例如,它用于测试 is None ,但在测试整数或字符串时可能会出错。但是在这种情况下,还有一个问题, x.dtypenp.float64 不是同一个类。

 isinstance(x.dtype, np.dtype)  # True
isinstance(np.float64, np.dtype) # False

x.dtype.__class__  # numpy.dtype
np.float64.__class__ # type

np.float64 其实是一个函数。 np.float64() 产生 0.0x.dtype() 产生错误。 (更正 np.float64 是一个类。)

在我的交互式测试中:

 x.dtype is np.dtype(np.float64)

返回 True 。但我不知道这是否普遍如此,或者只是某种本地缓存的结果。 dtype 文档提到了 dtype 属性:

dtype.num 21 种不同内置类型中每一种的唯一编号。

两种数据类型都为此给出 12 num

 x.dtype == np.float64

测试 True

此外,使用 type 有效:

 x.dtype.type is np.float64  # True


当我导入 ctypes 并执行 cast (与你的 xx_ )时,我得到一个错误:

ValueError:设置带有序列的数组元素。

我对 ctypes 了解不够,无法理解它正在尝试做什么。 It looks like it is doing a type conversion of the data pointer of xx_ , xx_.ctypes._as_parameter_ is the same number as xx_.__array_interface__['data'][0] .


numpy 测试代码中,我找到了这些 dtype 测试:

 issubclass(arr.dtype.type, (nt.integer, nt.bool_)
assert_(dat.dtype.type is np.float64)
assert_equal(A.dtype.type, np.unicode_)
assert_equal(r['col1'].dtype.kind, 'i')

numpy 文档也谈到

np.issubdtype(x.dtype, np.float64)
np.issubsctype(x, np.float64)

两者都使用 issubclass


进一步跟踪 c 代码表明 x.dtype == np.float64 被评估为:

 x.dtype.num == np.dtype(np.float64).num

即,标量类型转换为 dtype ,并与 .num 属性进行比较。该代码在 scalarapi.cdescriptor.cmultiarraymodule.c numpy / core / src / multiarray

原文由 hpaulj 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题