从 Python 函数返回多个值的替代方法

新手上路,请多包涵

在支持它的语言中返回多个值的规范方法通常是 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 许可协议

阅读 523
1 个回答

为此,在 2.6 中添加了 命名元组。另请参阅 os.stat 以获取类似的内置示例。

 >>> import collections
>>> Point = collections.namedtuple('Point', ['x', 'y'])
>>> p = Point(1, y=2)
>>> p.x, p.y
1 2
>>> p[0], p[1]
1 2

在最新版本的 Python 3(我认为是 3.6+)中,新的 typing 库获得了 NamedTuple 类,使命名元组更易于创建且功能更强大。继承自 typing.NamedTuple 允许您使用文档字符串、默认值和类型注释。

示例(来自文档):

 class Employee(NamedTuple):  # inherit from typing.NamedTuple
    name: str
    id: int = 3  # default value

employee = Employee('Guido')
assert employee.id == 3

原文由 A. Coady 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题