为什么 np.vectorize 处理单个元素时会调用函数两次?
数据小许
为什么会打印两次?
没有指定 otypes 时,np.vectorize 会先用第一个输入元素调用一次 f,根据返回值推断输出的数据类型。默认情况下,这次调用的结果不会被复用。随后逐元素计算时,第一个元素又会调用一次 f。
这个例子的执行过程是:
- 为推断输出类型,执行
f("input"),第一次打印hi input。 - 处理列表中的唯一元素时,再次执行
f,第二次打印hi input。 - 返回只有一个元素的结果数组,外层
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) 转换。
备注:内容仅供参考。
