在支持它的语言中返回多个值的规范方法通常是 tupling 。
选项:使用元组
考虑这个简单的例子:
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 }
只是最终成为 --- 的内部 __dict__
中的 ReturnValue
。
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__
不是为每个实例创建的。
选项:使用 数据类(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 而受到污染,但混合类型列表的想法一直让我感到不舒服。在这个特定的例子中,列表是 -not-mixed 类型,但可以想象它可能是。
据我所知,以这种方式使用的列表实际上对元组没有任何好处。 Python 中列表和元组之间唯一真正的区别是列表是 可变 的,而元组不是。
我个人倾向于继承函数式编程的约定:对任意数量的相同类型的元素使用列表,对固定数量的预定类型的元素使用元组。
问题
在冗长的序言之后,不可避免的问题来了。哪种方法(您认为)最好?
原文由 saffsd 发布,翻译遵循 CC BY-SA 4.0 许可协议
为此,在 2.6 中添加了 命名元组。另请参阅 os.stat 以获取类似的内置示例。
在最新版本的 Python 3(我认为是 3.6+)中,新的
typing
库获得了NamedTuple
类,使命名元组更易于创建且功能更强大。继承自typing.NamedTuple
允许您使用文档字符串、默认值和类型注释。示例(来自文档):