在支持多返回值的编程语言中,通常使用元组来实现。
选项:使用元组
考虑以下简单示例:
def f(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return (y0, y1, y2)
然而,当返回的值的数量增加时,这很快会变得棘手。如果您想返回四个或五个值怎么办?当然,您可以继续使用元组,但很容易忘记哪个值在哪里。在任何想要接收它们的地方解包它们也很丑陋。
选项:使用字典
下一个合乎逻辑的步骤似乎是引入某种“记录符号”。在Python中,显而易见的方法是通过 dict
实现。
考虑以下:
def g(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return {'y0': y0, 'y1': y1 ,'y2': y2}
仅为明确起见,y0、y1和y2只是抽象标识符。正如指出的那样,在实践中,您将使用有意义的标识符。
现在,我们有一种机制,可以投影出返回对象的特定成员。例如,
result['y0']
选项:使用类
然而,还有另一种选择。我们可以返回一个专门的数据结构。我已经在Python的语境中描述了这个方法,但我相信它同样适用于其他编程语言。事实上,如果你在C语言中工作,这可能是你唯一的选择。下面是具体实现:
class ReturnValue:
def __init__(self, y0, y1, y2):
self.y0 = y0
self.y1 = y1
self.y2 = y2
def g(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return ReturnValue(y0, y1, y2)
在Python中,前两者在管道方面可能非常相似 - 毕竟
{ y0,y1,y2 }
最终只是成为ReturnValue
的内部__dict__
中的条目。但是,Python为微小对象提供了一个额外的功能,即
__slots__
属性。该类可以表示为:class ReturnValue(object):
__slots__ = ["y0", "y1", "y2"]
def __init__(self, y0, y1, y2):
self.y0 = y0
self.y1 = y1
self.y2 = y2
来自Python参考手册:
__slots__
声明接受一系列实例变量,并为每个变量保留足够的空间以容纳一个值。由于不会为每个实例创建__dict__
,因此可以节省空间。
选项:使用dataclass(Python 3.7+)
使用Python 3.7的新数据类,返回一个具有自动添加的特殊方法、类型和其他有用工具的类:
@dataclass
class Returnvalue:
y0: int
y1: float
y3: int
def total_cost(x):
y0 = x + 1
y1 = x * 3
y2 = y0 ** y3
return ReturnValue(y0, y1, y2)
选项:使用列表
另一个我忽略的建议来自于蜥蜴比尔:
def h(x):
result = [x + 1]
result.append(x * 3)
result.append(y0 ** y3)
return result
这虽然是一种方法,但它是我最不喜欢的。我想我被接触 Haskell 污染了,但混合类型列表的想法始终让我感到不舒服。在这个特定的例子中,列表-不是-混合类型,但可以构想成是混合类型。
就我所知,在这种方式中使用的列表与元组相比并没有任何实质性的区别。Python 中列表和元组之间唯一的真正区别在于列表是 可变的,而元组则不是。
我个人倾向于沿用函数式编程的约定:对于同一类型的任意数量的元素,请使用列表,对于预定类型的固定数量的元素,请使用元组。
问题
在冗长的序言之后,必然会出现一个问题。你认为哪种方法最好?
y3
,但是除非声明了全局变量y3
,否则会导致NameError: global name 'y3' is not defined
。也许只用3
会更好? - hetepeperfany3
,这样也能达到同样的效果。 - okie