让Python函数根据参数数量干净地返回标量或列表

5 投票
5 回答
5187 浏览
提问于 2025-04-16 06:08

免责声明:我在寻找一个适用于Python 2.6的解决方案,如果有的话。

我想要一个函数,这个函数在接收一个值时返回一个单一的结果,而在接收多个值时返回一系列的结果:

>>> a = foo(1)
2
>>> b, c = foo(2, 5)
>>> b
3
>>> c
6

为了更清楚,这样做是为了让一些函数调用看起来更美观,而不是:

a, = foo(1)

或者

a = foo(1)[0]

现在,比较笨拙的解决方案大概是这样的:

def foo(*args):
    results = [a + 1 for a in args]
    return results if len(results) > 1 else results[0]

有没有什么语法糖(或者函数)可以让这个看起来更简洁?像下面这样的?

def foo(*args):
    return *[a + 1 for a in args]

5 个回答

0

这个代码可以处理0个或多个参数,我想这正是你想要的。

def foo(*args):
    return map(lambda x: x + 1, args) or [None]

补充说明:我修改了一下,增加了一个None列表,以防传入0个参数时出现问题。

7

如果你觉得这样更好,可以写一个装饰器来简化那个if语句:

import functools
def unpacked(method):
    @functools.wraps(method)
    def _decorator(*args):
        result = method(*args)
        return results if len(results) != 1 else results[0]
    return _decorator

使用方法:

@unpacked
def foo(*args):
    return [arg + 1 for arg in args]
6

你可以很简单地写一个叫做 scalify 的函数,如果列表里只有一个元素,它就返回这个元素。这个名字的意思就是把它变成一个标量(单一值)。

def scalify(l):
    return l if len(l) > 1 else l[0]

然后你可以像这样在你的函数里使用它:

def foo(*args):
    return scalify([a + 1 for a in args])

这样做是可以的,但我和那些建议你不要这样做的人是同一派的。原因之一是,这样做会让你无法遍历结果,除非你确定传入了至少两个项目。此外,如果你有一个列表,在调用这个函数时,你必须把列表拆开,这样就失去了它作为“列表”的特性,而且你也不能保证会得到一个列表回来。这些缺点在我看来远远超过了这种方法可能带来的任何好处。

撰写回答