NEP 34 — 禁止从 dtype=object 序列中推断#

作者:

Matti Picus

状态:

最终

类型:

标准轨道

创建:

2019-10-10

决议:

https://mail.python.org/pipermail/numpy-discussion/2019-October/080200.html

摘要#

当用户使用序列的序列创建数组时,有时会在匹配嵌套序列的长度方面出错,通常称为“参差不齐的数组”。在这里,我们将它们称为参差不齐的嵌套序列。通过 np.array([<ragged_nested_sequence>]) 创建此类数组且没有 dtype 关键字参数,现在将默认为 object-dtype 数组。将行为更改为改为引发 ValueError

动机和范围#

通过 np.array 使用列表的列表创建 numpy.ndarray 的用户可能会错误地传入长度不同的列表。目前,我们接受此输入并自动创建一个 dtype=object 的数组。这可能会令人困惑,因为它很少是想要的结果。将自动 dtype 检测更改为从不为参差不齐的嵌套序列(定义为序列的递归序列,其中同一级别上的并非所有序列都具有相同的长度)返回 object 将迫使用户如果确实希望创建 object 数组,则必须明确指定。请注意,liststuplesnd.ndarrays 都是序列[0]。例如,请参阅问题 5303

用法和影响#

此更改后,使用参差不齐的嵌套序列创建数组必须明确定义 dtype

>>> np.array([[1, 2], [1]])
ValueError: cannot guess the desired dtype from the input
>>> np.array([[1, 2], [1]], dtype=object)
# succeeds, with no change from current behaviour

弃用将影响任何内部调用 np.asarray 的调用。例如,assert_equal 函数族调用 np.asarray,因此用户必须更改如下代码:

np.assert_equal(a, [[1, 2], 3])

np.assert_equal(a, np.array([[1, 2], 3], dtype=object))

详细描述#

为了明确设置对象数组的形状,因为有时很难确定所需的形状,可以使用

>>> arr = np.empty(correct_shape, dtype=object)
>>> arr[...] = values

我们还将拒绝非序列和序列的混合序列,例如,所有这些都将被拒绝

>>> arr = np.array([np.arange(10), [10]])
>>> arr = np.array([[range(3), range(3), range(3)], [range(3), 0, 0]])

实现#

要更改的代码位于 PyArray_GetArrayParamsFromObject 和内部 discover_dimensions 函数中。PR 14794 中的第一个实现导致许多下游库失败,并在 1.18 版本发布之前被还原。随后,下游库修复了它们使用参差不齐数组的地方。重新实现成为PR 15119,该实现已合并到 1.19 版本中。

向后兼容性#

任何依赖于从参差不齐的嵌套序列创建对象数组的人都需要修改其代码。在弃用期间,当前行为将发出 DeprecationWarning

替代方案#

  • 我们可以继续使用当前情况。

  • 还建议向数组创建添加一个 kwarg depth,或者可能添加另一个数组创建 API 函数 ragged_array_object。目标是消除从 array([[1, 2], [1]], dtype=object) 创建对象数组时的歧义:返回的数组的形状应该是 (1,) 还是 (2,)?此 NEP 不处理该问题,只弃用在没有 dtype=object 的情况下使用 array 用于参差不齐的嵌套序列。参差不齐嵌套序列的用户将来可能会面临另一个弃用周期。理由:我们预计很少有用户打算那样使用参差不齐的数组,这从未被认为是 NumPy 数组的用例。用户最好使用另一个库或仅使用列表的列表。

  • 还建议弃用所有自动创建 object-dtype 数组,这需要为类似 np.array([Decimal(10), Decimal(10)]) 的内容添加显式的 dtype=object。这也超出了当前 NEP 的范围。理由:评估这种更大更改的影响更难,我们不确定这可能会影响多少用户。

讨论#

问题 5303 的评论表明,早在 2014 年,这就是意外行为。此后几年中提出了更改它的建议,但没有一个成功。 PR 14794 中的 WIP 实现似乎指出了这种方法的可行性。

参考文献和脚注#