从Python函数返回多个值的替代方法 [已关闭]

23 浏览
0 Comments

从Python函数返回多个值的替代方法 [已关闭]

在支持多个返回值的编程语言中,常见的方法是使用元组来返回多个值。\n选项:使用元组\n考虑以下简单的例子:\ndef f(x):\n y0 = x + 1\n y1 = x * 3\n y2 = y0 ** y3\n return (y0, y1, y2)\n然而,当返回的值的数量增加时,这种方法很快变得麻烦。如果你想返回四个或五个值怎么办?当然,你可以继续使用元组,但很容易忘记哪个值在哪里。在接收这些值的地方解包它们也相当丑陋。\n选项:使用字典\n下一个合乎逻辑的步骤似乎是引入某种“记录表示法”。在Python中,明显的方法是使用字典。\n考虑以下例子:\ndef g(x):\n y0 = x + 1\n y1 = x * 3\n y2 = y0 ** y3\n return {\'y0\': y0, \'y1\': y1 ,\'y2\': y2}\n(只是为了清楚起见,y0、y1和y2只是抽象标识符。正如指出的那样,在实践中,你会使用有意义的标识符。)\n现在,我们有了一种机制,可以从返回的对象中获取特定成员。例如,\nresult[\'y0\']\n选项:使用类\n然而,还有另一种选择。我们可以返回一个专门的结构。我将其放在Python的上下文中,但我相信它也适用于其他语言。实际上,如果你在C中工作,这可能是你唯一的选择。如下所示:\nclass ReturnValue:\n def __init__(self, y0, y1, y2):\n self.y0 = y0\n self.y1 = y1\n self.y2 = y2\ndef g(x):\n y0 = x + 1\n y1 = x * 3\n y2 = y0 ** y3\n return ReturnValue(y0, y1, y2)\n在Python中,前两种方法在管道方面可能非常相似-毕竟,{ y0, y1, y2 }最终只是成为ReturnValue的内部__dict__的条目。\n但是,Python还提供了另一个特性,适用于小对象的__slots__属性。该类可以表示为:\nclass ReturnValue(object):\n __slots__ = [\"y0\", \"y1\", \"y2\"]\n def __init__(self, y0, y1, y2):\n self.y0 = y0\n self.y1 = y1\n self.y2 = y2\n根据Python参考手册:\n“__slots__”声明采用一个实例变量序列,并为每个实例保留足够的空间来容纳每个变量的值。由于每个实例都不会创建__dict__,因此可以节省空间。\n选项:使用dataclass(Python 3.7+)\n使用Python 3.7的新数据类,返回一个带有自动添加的特殊方法、类型和其他有用工具的类:\n@dataclass\nclass Returnvalue:\n y0: int\n y1: float\n y3: int\ndef total_cost(x):\n y0 = x + 1\n y1 = x * 3\n y2 = y0 ** y3\n return ReturnValue(y0, y1, y2)\n选项:使用列表\n另一个被忽视的建议来自于Bill the Lizard:\ndef h(x):\n result = [x + 1]\n result.append(x * 3)\n result.append(y0 ** y3)\n return result\n然而,这是我最不喜欢的方法。我想我被Haskell的影响所污染,但混合类型列表的想法一直让我感到不舒服。在这个特定的例子中,列表是不同类型的,但它可能是混合类型的。\n在我看来,以这种方式使用列表与元组相比并没有什么区别。Python中列表和元组的唯一真正区别是列表是可变的,而元组是不可变的。\n我个人倾向于延续函数式编程的惯例:对于同一类型的任意数量的元素使用列表,对于固定数量的确定类型的元素使用元组。\n问题\n在冗长的前言之后,不可避免地出现了问题。你认为哪种方法最好?

0
0 Comments

在Python中,有时候我们需要从一个函数中返回多个值。有多种方法可以实现这一点。许多答案建议返回一个集合,比如字典或列表。你也可以省略额外的语法,直接写出返回值,用逗号分隔。需要注意的是,这实际上返回的是一个元组。

def f():
    return True, False
x, y = f()
print(x)
print(y)

运行以上代码,输出结果为:

True
False

其实,你仍然是在返回一个集合,只不过这次是一个元组。为了更清晰明了,我更喜欢使用括号。可以尝试运行`type(f())`,你会发现返回的类型是``。

其实,我们并不需要显式地指明返回的是一个元组。重要的是我们可以使用这种方式返回多个值。就好像交换变量的值时可以省略括号,例如`x, y = y, x`,多重赋值时可以省略括号,例如`x, y = 0, 1`,等等。当然,在底层,这些操作都会生成元组,但是没有必要显式地指明这一点,因为元组并不是重点。在Python的教程中,早在介绍元组之前,就已经介绍了多重赋值。

在Python中,任何以逗号分隔的值序列都可以被视为一个元组,不论是否使用括号将它们括起来。所以在这里既没有显式的也没有隐式的操作。`a, b, c`和`(a, b, c)`都是元组。当你返回这样的值时,并不会在底层生成元组,因为它仅仅是一个普通的简单元组。问题的提问者已经提到了元组,所以他提到的内容和这个答案没有任何区别。

这实际上是问题中提出的第一个选项。对于问题中两次提出的问题(“如何返回多个值?”和“你是如何返回多个值的?”),这个答案都有了回答。问题的文本有时会有所改变。这是一个基于观点的问题。

0
0 Comments

在Python中,函数通常只能返回一个值。然而,在某些情况下,我们可能需要从函数中返回多个值。这是一个常见的问题,因为它使得代码更加清晰和易于理解。这篇文章将讨论在Python中返回多个值的替代方法以及它们的优劣势。

对于小型项目,最简单的方法是使用元组。当元组的管理变得困难时,我会将值分组为逻辑结构。然而,使用字典和ReturnValue对象的建议方法可能是错误的或过于简单。

返回一个具有键"y0"、"y1"、"y2"等的字典与使用元组没有任何优势。返回一个具有属性.y0、.y1、.y2等的ReturnValue实例也没有任何优势。如果想要取得进展,就需要给事物命名,并且无论如何都可以使用元组来完成这个任务:

def get_image_data(filename):
    [snip]
    return size, (format, version, compression), (width,height)
size, type, dimensions = get_image_data(x)

在我看来,除了元组之外,唯一好的技术是返回具有适当方法和属性的真实对象,就像从re.match()或open(file)中获得的那样。

关于"返回具有键y0、y1、y2等的字典与使用元组没有任何优势"的说法:字典的优势在于可以添加字段到返回的字典中,而不会破坏现有的代码。

关于"返回具有键y0、y1、y2等的字典与使用元组没有任何优势"的说法:它还更易读,更不容易出错,因为你可以根据名称而不是位置来访问数据。

我们可以使用元组、字典或具有方法和属性的真实对象来返回多个值。选择哪种方法取决于代码的复杂性、可读性和可扩展性的要求。无论使用哪种方法,都应该根据具体情况来选择,并且要确保代码易于理解和维护。

0
0 Comments

在Python中,有时候我们需要从函数中返回多个值。然而,Python原生的函数只能返回一个值。因此,我们需要找到一种解决办法来返回多个值。

Python 2.6版本引入了namedtuple来解决这个问题。namedtuple是一个工厂函数,可以用来创建具有命名字段的元组。它可以通过字段名称或者索引来访问元组的值。例如,我们可以使用namedtuple创建一个Point类,并为其定义x和y两个字段。然后我们可以通过字段名或者索引来访问Point对象的值。

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

在Python 3.6及以上的版本中,新的typing库引入了NamedTuple类来更加方便地创建和使用namedtuple。通过继承typing.NamedTuple,我们可以在定义namedtuple时使用文档字符串、默认值和类型注解。例如,我们可以定义一个Employee类,它继承自typing.NamedTuple,并具有name和id两个字段。其中id字段有默认值3。

from typing import NamedTuple
class Employee(NamedTuple):
    name: str
    id: int = 3
employee = Employee('Guido')
assert employee.id == 3

以上是两种常用的方法来从Python函数中返回多个值的解决方案。namedtuple适用于返回大量结果的情况,可以减少内存占用。而typing.NamedTuple则提供了更多的功能,如默认值和类型注解。

除了以上解决方案,还有一种提议使用types.SimpleNamespace的方法来返回多个值。types.SimpleNamespace是一个类似于字典的对象,可以在创建之后添加值。这意味着我们可以在获得结果时立即将其添加到retval Namespace中,而不需要等到一次性将它们放入namedtuple中。这在大型函数中可以减少混乱。

然而,types.SimpleNamespace是一个增强的字典,每个实例的内存消耗较高,创建成本也较高,并且没有像元组那样的解包能力。

namedtuple和typing.NamedTuple是从Python函数中返回多个值的两种常用解决方案。它们分别适用于不同的场景,具有不同的优势和劣势。而types.SimpleNamespace作为一个字典的扩展,虽然也可以用来返回多个值,但相比于前两者在内存消耗和创建成本方面存在一些不足。

0