如何使函数的返回值可迭代?

时间:2019-04-28 15:39:47

标签: python arrays numpy

我正在尝试编写一个可以处理各种数量和类型的返回值的装饰器,但是我在处理数字/数字的可重复性时遇到了麻烦。

说我想让我的装饰器对其装饰的函数的每个返回值进行“ +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)

最后,我的问题是:

当这些值可以具有不同的数量和不同的类型时,是否有一种优雅的方法可迭代该函数的返回值?

我想我可以测试每个返回值的类型,但是看起来也不是很优雅。

欢呼

1 个答案:

答案 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,然后在其中修改数据