我正在尝试编写一个可以处理各种数量和类型的返回值的装饰器,但是我在处理数字/数字的可重复性时遇到了麻烦。
说我想让我的装饰器对其装饰的函数的每个返回值进行“ +1”运算。我找到了这样做的方法,尽管我并不觉得它很优雅(尤其是“ try / except”块,以及“如果len(x)> 1 else x [0]”行则返回“ tuple(x))):
# Plus-one decorator
def plus_one_decorator(func):
"""Decorator that adds one to each returned values"""
def decorated(*args, **kwargs):
raw_res = func(*args, **kwargs)
# Making raw_res iterable (since it could be any length)
try:
raw_res = tuple(raw_res)
except:
raw_res = [raw_res]
# Creating a list to store the decorated-outputs
output_list = []
for res in raw_res:
output_list.append(res + 1)
# Sugar to not return a one-tuple
return tuple(output_list) if len(output_list) > 1 else output_list[0]
return decorated
# Decorated func
dec_minus = plus_one_decorator(lambda x: -x)
dec_dbl_tpl = plus_one_decorator(lambda x: (x*2, x*3))
# Checking
print(dec_minus(1)) # >>> 0 (as expected)
print(dec_dbl_tpl(3)) # >>> 7, 10 (as expected)
所以这确实适用于纯数字,但是如果我将其与numpy.ndarray一起使用会怎样:
import numpy as np
foo = np.array([1, 1, 1])
print(dec_minus(foo)) # >>> (0, 0, 0) (! Expected array([0, 0, 0]))
print(dec_dbl_tpl(foo)) # >>> (array([3, 3, 3]), array([4, 4, 4])) (as expected)
对于第二个返回元组的函数,它确实按预期工作,因为原始返回的值已经是元组(因为tuple((array_1,array_2))->(array_1,array_2))。但是,ndarray array([0, 0, 0])
被转换为元组(0, 0, 0)
。
最后,我的问题是:
当这些值可以具有不同的数量和不同的类型时,是否有一种优雅的方法可迭代该函数的返回值?
我想我可以测试每个返回值的类型,但是看起来也不是很优雅。
欢呼
答案 0 :(得分:1)
是的,有。
例如:
from collections.abc import Iterable
from copy import deepcopy
...
# in your decorator
if not isinstance(raw_res, Iterable):
raw_res = [raw_res]
output = deepcopy(raw_res)
for i, res in enumerate(output):
output[i] = res + 1
return output if len(output) > 1 else output[0]
在您的示例中,您创建了一个名为output_list
的值的列表,但是您应该将所有数据复制到output
,然后在其中修改数据