如何在预期多个返回值时优雅地从函数返回
这个 myFunct
函数应该返回两个值。返回的这两个值会被存到 var_1
和 var_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 个回答
来看看一个很棒的装饰器吧!
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)
虽然这个问题有争议,但通常认为在代码中保持一个单一的退出点是个好习惯。也就是说,最好只用一个返回语句。你可以这样做:
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
应该只用来表示类似于空列表的情况,也就是说,返回什么都没有是这个函数预期的结果之一。
如果有什么地方出错了,正确的做法是抛出一个异常。不过,如果你真的不想这么做,你可以选择其他方法:
try:
var_1, var_2 = myFunct(5)
except TypeError:
var_1, var_2 = (None,None)
补充:
也许你需要考虑一下,如果你的 var_1
和 var_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"
把结果存储在一个变量里,然后根据需要再展开使用。
result = myFunct(5)
var_1, var_2 = (None, None) if result is None else result