我正在尝试编写一个可以处理各种数量和类型的返回值的装饰器,而我在处理数字/数字的迭代时遇到了麻烦。
假设我希望我的装饰器对其装饰的函数的每个返回值进行“ +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))。但是,ndarrayarray([0, 0, 0])
将转换为元组(0, 0, 0)
。
所以,最后,我的问题是:
当这些值可以具有不同的数量和不同的类型时,是否有一种优雅的方法可迭代该函数的返回值?
我猜我可以测试每个返回值的类型,但是看起来也不是很优雅。
干杯
就在这里。
例如:
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
,然后在其中修改数据
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句