从 python 函数分配可变数量 returns 的优雅方式
Elegant way to assign a variable number of returns from a python function
我正在使用一个 python 库,它的函数以列表形式返回结果。根据实验配置,此列表由一个或两个元素组成。在这种情况下,分配函数输出的直接方法如下:
bbox, segm = None, None
results = test_model() # returns a list with either one or two elements
bbox = results[0]
if len(results) > 1:
segm = results[1]
# [some other code here]
if segm is not None:
plot(segm)
然而,这似乎很冗长,因为我们需要先将 bbox
和 segm
都初始化为 None
,然后计算 if len(results) > 1
。有什么 pythonic 方法可以避免这种情况吗?理想情况下,像这样的东西会非常好:
bbox, segm = test_model() # returns a list with either one or two elements
if segm is not None:
plot(segm)
您可以使用 structural pattern matching,在 Python 3.10 中可用:
match test_model():
case [bbox, segm]:
plot(segm)
case bbox:
pass
但是,如果test_module
总是returns一个元组,你可以使用解包:
bbox, *segm = test_model()
现在,如果 text_model
返回一个值,segm
将是一个空列表 ([]
)。但是,如果它返回两个值,segm
将包含一个元素。因此,您的完整代码可以变成:
bbox, *segm = test_model()
if segm:
plot(segm[0])
您可以扩展 return
list
一个额外的元素,然后切掉 2 个需要的元素。
def foo(boolean):
if boolean:
return [True, True]
return [False]
bar, baz = (foo(False) + [None])[:2]
print(bar, baz) # False None
bar, baz = (foo(True) + [None])[:2]
print(bar, baz) # True True
pythonic 方式将是 *
如 @Ajax1234 提到的那样解包,但这是另一种选择。
如果您可以控制函数定义,您也可以添加装饰器。
def returns_two(func):
def wrapper(*args):
return (func(*args) + [None])[:2]
return wrapper
@returns_two
def foo(boolean):
if boolean:
return [True, True]
return [False]
bar, baz = foo(False)
print(bar, baz) # False None
bar, baz = foo(True)
print(bar, baz) # True True
如果您使用的是 Python 3.10,请使用 。
否则,您的首要任务是编写易于阅读的内容,而不是做任何花哨的事情。像这样分配给元组会起作用:
try:
bbox, segment = results
except ValueError:
bbox, segment = results[0], None
这有很多优点:
- 你一目了然。
- 如果列表的长度不是 1 或 2,您将得到一个错误,而不是静默失败。
处理异常时,将异常用于实际异常的情况是有意义的。所以如果你希望一个列表项有更多的结果,你可以反过来写:
try:
bbox, = results
segment = None
except ValueError:
bbox, segment = results
还有两种方法,如果test_model()
returns只有一个值,则将None
分配给segm
:
bbox, segm, *_ = *test_model(), None
bbox, segm = (*test_model(), None)[:2]
我正在使用一个 python 库,它的函数以列表形式返回结果。根据实验配置,此列表由一个或两个元素组成。在这种情况下,分配函数输出的直接方法如下:
bbox, segm = None, None
results = test_model() # returns a list with either one or two elements
bbox = results[0]
if len(results) > 1:
segm = results[1]
# [some other code here]
if segm is not None:
plot(segm)
然而,这似乎很冗长,因为我们需要先将 bbox
和 segm
都初始化为 None
,然后计算 if len(results) > 1
。有什么 pythonic 方法可以避免这种情况吗?理想情况下,像这样的东西会非常好:
bbox, segm = test_model() # returns a list with either one or two elements
if segm is not None:
plot(segm)
您可以使用 structural pattern matching,在 Python 3.10 中可用:
match test_model():
case [bbox, segm]:
plot(segm)
case bbox:
pass
但是,如果test_module
总是returns一个元组,你可以使用解包:
bbox, *segm = test_model()
现在,如果 text_model
返回一个值,segm
将是一个空列表 ([]
)。但是,如果它返回两个值,segm
将包含一个元素。因此,您的完整代码可以变成:
bbox, *segm = test_model()
if segm:
plot(segm[0])
您可以扩展 return
list
一个额外的元素,然后切掉 2 个需要的元素。
def foo(boolean):
if boolean:
return [True, True]
return [False]
bar, baz = (foo(False) + [None])[:2]
print(bar, baz) # False None
bar, baz = (foo(True) + [None])[:2]
print(bar, baz) # True True
pythonic 方式将是 *
如 @Ajax1234 提到的那样解包,但这是另一种选择。
如果您可以控制函数定义,您也可以添加装饰器。
def returns_two(func):
def wrapper(*args):
return (func(*args) + [None])[:2]
return wrapper
@returns_two
def foo(boolean):
if boolean:
return [True, True]
return [False]
bar, baz = foo(False)
print(bar, baz) # False None
bar, baz = foo(True)
print(bar, baz) # True True
如果您使用的是 Python 3.10,请使用
否则,您的首要任务是编写易于阅读的内容,而不是做任何花哨的事情。像这样分配给元组会起作用:
try:
bbox, segment = results
except ValueError:
bbox, segment = results[0], None
这有很多优点:
- 你一目了然。
- 如果列表的长度不是 1 或 2,您将得到一个错误,而不是静默失败。
处理异常时,将异常用于实际异常的情况是有意义的。所以如果你希望一个列表项有更多的结果,你可以反过来写:
try:
bbox, = results
segment = None
except ValueError:
bbox, segment = results
还有两种方法,如果test_model()
returns只有一个值,则将None
分配给segm
:
bbox, segm, *_ = *test_model(), None
bbox, segm = (*test_model(), None)[:2]