如何在预期多个返回值时优雅地从函数返回

1 投票
4 回答
1305 浏览
提问于 2025-04-18 08:40

这个 myFunct 函数应该返回两个值。返回的这两个值会被存到 var_1var_2 里。

为了检查是否有错误,我在这个函数内部使用了很多 if/else: return 的语句。比如,我写了简单的 if arg<10: return,这会返回一个单一的 None,这就会引发一个错误:TypeError: 'NoneType' object is not iterable。因为我有两个变量 var_1, var_2 = myFunct(5),它们期待得到两个返回值,但实际上只得到了一个 None

为了避免出现这样的错误,我需要使用以下的语法:

if arg<10: return None, None

不过我觉得这个写法挺难看的。

我在想有没有更好的方法来做到这一点...

def myFunct(arg):
    if arg<10:
        return
    return 100, 200

var_1, var_2 = myFunct(5)

4 个回答

2

来看看一个很棒的装饰器吧!

import decorator

def default_return_value(value):
    @decorator.decorator
    def decorate(f, *args, **kwargs):
        x = f(*args, **kwargs)
        return value if x is None else x
    return decorate

def returns_tuple(size):
    return default_return_value(tuple([None] * size))

@returns_tuple(size=2)
def myFunct(arg):
    if arg >= 10:
        return 100, 200

>>> myFunct(15)
(100, 200)

>>> myFunct(5)
(None, None)
2

虽然这个问题有争议,但通常认为在代码中保持一个单一的退出点是个好习惯。也就是说,最好只用一个返回语句。你可以这样做:

def myFunc(arg):
    result1, result2 = None, None
    if not arg < 10:
        result1, result2 = 100,200
    return result1, result2

显然,你这个简单的例子可以用更简洁的方式来写,比如使用更“Python风格”的方法:

def myFunc(arg):
    return (None, None) if arg < 10 else (100,200)

不过,对于我那些复杂的函数来说,保持单一的退出点是个值得养成的好习惯。

正如其他人提到的,抛出异常是表示函数遇到错误的最“Python风格”的方式。一般来说,返回None应该只用来表示类似于空列表的情况,也就是说,返回什么都没有是这个函数预期的结果之一。

3

如果有什么地方出错了,正确的做法是抛出一个异常。不过,如果你真的不想这么做,你可以选择其他方法:

try:
    var_1, var_2 = myFunct(5)
except TypeError:
    var_1, var_2 = (None,None)

补充:

也许你需要考虑一下,如果你的 var_1var_2 确实是 None(也就是没有值),你打算怎么处理它们。如果你要继续进行某个计算,而 None 是一个有效的输入,那么返回 return None,None 可能是合适的做法。但是,如果这是一个异常情况,你想说明结果是 None,并且要做一些完全不同的事情(而不是返回两个值),那么你可以这样做:

result = myFunct(5)
if result:
    var_1,var_2=result
    do_more_stuff_here_with(var_1 and var_2) # logical and :)
else:
    print "myFunct(5) failed - check (and if necessary adjust) the phase of the moon"
1

把结果存储在一个变量里,然后根据需要再展开使用。

result = myFunct(5)
var_1, var_2 = (None, None) if result is None else result

撰写回答