【问题标题】:What is the Python 3 way to ensure the correct dimension of array arguments?确保数组参数正确维度的 Python 3 方法是什么?
【发布时间】:2019-04-15 13:08:01
【问题描述】:

在我的新手 Python 3.7 项目中,许多函数中的参数都是 numpy.ndarray 的。这些必须是二维r x n 矩阵。行维度r 是必不可少的:一些函数需要1 x n 向量,另一些需要2 x n 矩阵,r 最多三个甚至更多。还有为任何r x n 数组定义的函数。 (列维度n 对于设计目的来说不是必需的。)

根据我的 Matlab 经验,此要求可能会令人困惑且容易出错。所以我考虑了以下方法:

  1. 记录方法参数(当然!)
  2. 单元测试(当然!)
  3. 在某些函数中进行验证并抛出异常。 (但是,这不是很实用,也不是很高效。)
  4. 定义数据类:OneRowTwoRowsThreeRowsFourPlusRows。每个都有一个ndarray 字段,在构造函数中验证。好处包括类型提示和更好的领域建模,如 DDD。缺点是额外的复杂性。

问题:鉴于 Python 3 中引入的类型提示以及函数式编程的趋势,当前解决此问题的 Python 方法是什么?

【问题讨论】:

  • assert a.shape[0] == r?
  • 类型提示尚未在 numpy 中实现。
  • 尽可能编写 numpy 代码以处理“任何”维度。如果不测试 ndimshape 就可以了。无论是引发错误还是调整形状都是您的选择。
  • 根据 3.) 这有时对于获得 SIMD 向量化或在 jit 编译代码中展开小循环是必要的,因此可以显着提高速度。 github.com/numba/llvmlite/issues/270

标签: python arrays numpy type-hinting


【解决方案1】:

Python 最棒的地方之一是duck typing,而 Numpy 通常与这种设计方法非常兼容。假设您有一个纯矢量函数vecfunc。您可以在函数的开头添加一些样板,将任何一维数组膨胀为1 x n 向量:

def vecfunc(arr):
    if arr.ndim==1:
        arr = arr[None, :]

    ...function body goes here...

这将避免由于arr 的维度太少而导致的任何问题,并且在大多数情况下可能仍会提供正确的行为。但是,它不会做任何事情来阻止用户传入,例如 r x n x m 数组或 15 x n 数组。最终,你将不得不使用3. 的方法来处理一堆这样的东西,并在看起来合适的地方抛出一些异常。例如:

def vecfunc(arr):
    if not 0 < arr.ndim < 3:
        raise ValueError("arr must have ndim of 1 or 2. arr.ndim: %d" % arr.ndim)
    elif arr.ndim==1:
        arr = arr[None, :]

如果它让您感觉更好,numpyscipy 的代码库在许多函数中都在需要它们的时间和地点进行了这些类型的基于形状的异常检查。

当然,您总是可以在开发任何给定函数的最后一刻才添加这些类型的异常检查。您可能会对产生合理行为的输入范围感到惊讶。

如果你对类型注解不感兴趣,你可以通过writing your code using Cython 获得类似的东西。例如,如果您想要一个只接受二维整数数组的 add 函数,您可以在 .pyx 文件中编写以下函数:

import numpy as np

def add(long[:, :] arr1, long[:, :] arr2):
    assert tuple(arr1.shape) == tuple(arr2.shape)

    result = np.zeros((arr1.shape[0], arr1.shape[1]), dtype=np.long)
    cdef long[:, :] result_view = result

    for x in range(arr1.shape[0]):
        for y in range(arr1.shape[1]):
            result_view[x, y] = arr1[x, y] + arr2[x, y]

    return result

有关编写和编译 Cython 的更多详细信息,请参阅上面链接的文档。

这与其说是“类型注释”,不如说是真正的强类型,但它可以做你想做的事。可悲的是,我无法找到一种方法来修复单个维度的大小,只是维度的总数。

【讨论】:

  • 好答案。也许我应该停止在 Python 中思考“静态类型”。
猜你喜欢
  • 1970-01-01
  • 2017-06-03
  • 1970-01-01
  • 1970-01-01
  • 2010-11-11
  • 2021-03-31
  • 2014-03-06
  • 1970-01-01
  • 2016-11-05
相关资源
最近更新 更多