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

莫金

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

假设我希望我的装饰器对其装饰的函数的每个返回值进行“ +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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章