在支持它的语言中返回多个值的规范方式通常是元组。
考虑这个简单的例子:
def f(x):y0 = x + 1y1 = x * 3y2 = y0 ** y3return (y0, y1, y2)
然而,随着返回值数量的增加,这很快就会出现问题。如果你想返回四个或五个值怎么办?当然,你可以继续对它们进行元组化,但很容易忘记哪个值在哪里。在任何你想接收它们的地方解包它们也是相当丑陋的。
下一个合乎逻辑的步骤似乎是引入某种“记录符号”。在Python中,显而易见的方法是通过dict
。
考虑以下几点:
def g(x):y0 = x + 1y1 = x * 3y2 = y0 ** y3return {'y0': y0, 'y1': y1 ,'y2': y2}
(需要说明的是,y0、y1和y2只是抽象标识符。如前所述,在实践中您将使用有意义的标识符。)
现在,我们有了一种机制,我们可以通过这种机制投影出返回对象的特定成员。例如,
result['y0']
然而,还有另一种选择。我们可以返回一个专门的结构。我已经在Python的上下文中构建了这个,但我相信它也适用于其他语言。事实上,如果你用C工作,这很可能是你唯一的选择。下面是:
class ReturnValue:def __init__(self, y0, y1, y2):self.y0 = y0self.y1 = y1self.y2 = y2
def g(x):y0 = x + 1y1 = x * 3y2 = y0 ** y3return 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 = y0self.y1 = y1self.y2 = y2
__slots__
声明接受一系列实例变量,并在每个实例中保留足够的空间来保存每个变量的值。节省空间是因为__dict__
不是为每个实例创建的。
使用Python 3.7的新数据类,返回一个带有自动添加的特殊方法、键入和其他有用工具的类:
@dataclassclass Returnvalue:y0: inty1: floaty3: int
def total_cost(x):y0 = x + 1y1 = x * 3y2 = y0 ** y3return ReturnValue(y0, y1, y2)
我忽略的另一个建议来自蜥蜴比尔:
def h(x):result = [x + 1]result.append(x * 3)result.append(y0 ** y3)return result
不过,这是我最不喜欢的方法。我想我接触过Haskell,但混合类型列表的想法一直让我感到不舒服。在这个特殊的例子中,列表不是混合类型,但可以想象它可能是。
据我所知,以这种方式使用的列表实际上对元组没有任何好处。Python中列表和元组之间唯一真正的区别是列表是可变,而元组不是。
我个人倾向于继承函数式编程的约定:对任意数量的相同类型的元素使用列表,对固定数量的预定类型的元素使用元组。
在冗长的序言之后,不可避免的问题来了。哪种方法(你认为)最好?