PAYATHON 2026

为什么 np.vectorize 处理单个元素时会调用函数两次?

数据小许

为什么会打印两次?

没有指定 otypes 时,np.vectorize 会先用第一个输入元素调用一次 f,根据返回值推断输出的数据类型。默认情况下,这次调用的结果不会被复用。随后逐元素计算时,第一个元素又会调用一次 f。

这个例子的执行过程是:

  1. 为推断输出类型,执行 f("input"),第一次打印 hi input。
  2. 处理列表中的唯一元素时,再次执行 f,第二次打印 hi input。
  3. 返回只有一个元素的结果数组,外层 print 输出 ['input']。

方法一:明确指定 otypes

如果知道函数的返回类型,可以用 otypes 指定输出类型,省去试调用。当前示例返回字符串,可以这样写:

import numpy as np

def f(x):
    print(f"hi {x}")
    return x

vectorized_f = np.vectorize(f, otypes=[str])
print(vectorized_f(["input"]))

输出为:

hi input
['input']

otypes 指定输出数组的数据类型,应根据函数的实际返回值选择。这里的 [str] 适用于示例中的字符串输出。

方法二:使用 cache=True

如果仍希望由 np.vectorize 推断输出类型,可以启用 cache=True,复用类型推断时首次调用的结果:

vectorized_f = np.vectorize(f, cache=True)
print(vectorized_f(["input"]))

这个例子同样只会打印一次 hi input。

这里的缓存只用于避免类型推断后重复计算第一个元素,不是通用的参数记忆缓存。遇到重复输入或再次调用 vectorized_f 时,仍然可能执行 f。

使用时要注意什么?

np.vectorize 主要是为了方便处理数组输入和广播,计算本质上仍是逐元素调用 Python 函数,通常不能依靠它获得性能提升。

对于打印日志、写文件或修改外部状态这类带副作用的函数,要留意默认的类型推断会额外执行一次函数。如果要求每个输入严格对应一次操作,显式循环往往更直观:

result = [f(x) for x in ["input"]]
print(result)

这里得到的是 Python 列表;如果需要 NumPy 数组,可以再用 np.array(result) 转换。

备注:内容仅供参考。