如何在Python中返回多个值?

时间:2022-03-19 07:43:04

The canonical way to return multiple values in languages that support it is often tupling.

在支持它的语言中返回多个值的标准方法通常是tupling。

Option: Using a tuple

Consider this trivial example:

考虑一下这个简单的例子:

def f(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return (y0,y1,y2)

However, this quickly gets problematic as the number of values returned increases. What if you want to return four or five values? Sure, you could keep tupling them, but it gets easy to forget which value is where. It's also rather ugly to unpack them wherever you want to receive them.

但是,随着返回值的增加,这很快就会产生问题。如果你想返回四五个值呢?当然,你可以继续把它们翻倍,但是很容易忘记哪个值在哪。在你想要接收它们的地方打开它们,也相当难看。

Option: Using a dictionary

The next logical step seems to be to introduce some sort of 'record notation'. In python, the obvious way to do this is by means of a dict.

下一个逻辑步骤似乎是引入某种“记录符号”。在python中,最明显的方法是通过命令。

Consider the following:

考虑以下:

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }

(edit- Just to be clear, y0, y1 and y2 are just meant as abstract identifiers. As pointed out, in practice you'd use meaningful identifiers)

(编辑-只是要清楚,y0, y1和y2只是抽象的标识符。如前所述,在实践中,您将使用有意义的标识符)

Now, we have a mechanism whereby we can project out a particular member of the returned object. For example,

现在,我们有了一个机制,我们可以设计出返回对象的特定成员。例如,

result['y0']

Option: Using a class

However, there is another option. We could instead return a specialized structure. I've framed this in the context of Python, but I'm sure it applies to other languages as well. Indeed, if you were working in C this might very well be your only option. Here goes:

然而,还有另外一个选择。我们可以返回一个专门的结构。我在Python的上下文中已经把它框起来了,但是我确信它也适用于其他语言。事实上,如果你在C工作,这很可能是你唯一的选择。是:

class ReturnValue(object):
  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)

In python the previous two are perhaps very similar in terms of plumbing- After all { y0, y1, y2 } just end up being entries in the internal __dict__ of the ReturnValue.

在python中,前两者在管道方面可能非常相似——在所有{y0, y1, y2}最后都是在ReturnValue内部的__dict__中。

There is one additional feature provided by Python though for tiny objects, the __slots__ attribute. The class could be expressed as:

Python提供了一个额外的特性,不过对于小对象,__slots__属性。该类可以表示为:

class ReturnValue(object):
  __slots__ = ["y0", "y1", "y2"]
  def __init__(self, y0, y1, y2):
     self.y0 = y0
     self.y1 = y1
     self.y2 = y2

From the Python Reference Manual:

从Python参考手册:

The __slots__ declaration takes a sequence of instance variables and reserves just enough space in each instance to hold a value for each variable. Space is saved because __dict__ is not created for each instance.

__slots_声明接受一个实例变量序列,并在每个实例中保留足够的空间,以便为每个变量保存一个值。存储空间是因为__dict__不是为每个实例创建的。

Option: Using a list

Another suggestion which I'd overlooked comes from Bill the Lizard:

另一个我忽略了的建议是关于蜥蜴的:

def h(x):
  result = [x + 1]
  result.append(x * 3)
  result.append(y0 ** y3)
  return result

This is my least favorite method though. I suppose I'm tainted by exposure to Haskell, but the idea of mixed-type lists has always felt uncomfortable to me. In this particular example the list is -not- mixed type, but it conceivably could be. A list used in this way really doesn't gain anything with respect to the tuple as far as I can tell. The only real difference between lists and tuples in Python is that lists are mutable, wheras tuples are not. I personally tend to carry over the conventions from functional programming: use lists for any number of elements of the same type, and tuples for a fixed number of elements of predetermined types.

这是我最不喜欢的方法。我想我是受了Haskell的影响,但是混合类型列表的想法总是让我觉得不舒服。在这个特殊的例子中,列表是-不是混合类型,但是可以想象它可能是。以这种方式使用的列表实际上并没有获得关于元组的任何东西,就我所知。在Python中,列表和元组之间唯一真正的区别是列表是可变的,而元组则不是。我个人倾向于从函数式编程中继承约定:对相同类型的任意数量的元素使用列表,并对预定类型的固定数量的元素进行元组。

Question

After the lengthy preamble, comes the inevitable question. Which method (do you think) is best?

在冗长的序言之后,出现了不可避免的问题。你认为哪种方法最好?

I've typically found myself going the dictionary route because it involves less set-up work. From a types perspective however, you might be better off going the class route, since that may help you avoid confusing what a dictionary represents. On the other hand, there are some in the Python community that feel implied interfaces should be preferred to explicit interfaces, at which point the type of the object really isn't relevant, since you're basically relying on the convention that the same attribute will always have the same meaning.

我通常发现自己走字典的路线,因为它涉及较少的设置工作。但是,从类型的角度来看,您最好还是选择类路径,因为这样可以帮助您避免混淆字典所代表的内容。另一方面,在Python社区中,有些人认为隐含的接口应该被首选为显式接口,在这一点上,对象的类型实际上并不相关,因为您基本上是依赖于相同的属性将始终具有相同的含义的约定。

So, how do -you- return multiple values in Python?

那么,如何在Python中返回多个值?

13 个解决方案

#1


464  

Named tuples were added in 2.6 for this purpose. Also see os.stat for a similar builtin example.

为此,在2.6中添加了命名元组。也看到操作系统。这是一个类似的内置例子。

>>> 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

#2


151  

For small projects I find it easiest to work with tuples. When that gets too hard to manage (and not before) I start grouping things into logical structures, however I think your suggested use of dictionaries and ReturnValue objects is wrong (or too simplistic).

对于小型项目,我发现使用元组是最容易的。当这变得很难管理(而不是以前)时,我开始将事情分组到逻辑结构中,但是我认为您建议使用字典和ReturnValue对象是错误的(或者过于简单)。

Returning a dictionary with keys y0, y1, y2 etc doesn't offer any advantage over tuples. Returning a ReturnValue instance with properties .y0 .y1 .y2 etc doesn't offer any advantage over tuples either. You need to start naming things if you want to get anywhere, and you can do that using tuples anyway:

返回一个带键y0、y1、y2等的字典并不比元组有任何优势。返回具有属性的ReturnValue实例。y0 .y1 .y2等也没有提供任何优于元组的优点。你需要开始命名东西,如果你想要得到任何地方,你可以使用元组来做:

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

IMHO, the only good technique beyond tuples is to return real objects with proper methods and properties, like you get from re.match() or open(file).

除了tuple之外,唯一的好方法是使用正确的方法和属性返回真正的对象,就像从re.match()或open(文件)中得到的一样。

#3


85  

A lot of the answers suggest you need to return a collection of some sort, like a dictionary or a list. You could leave off the extra syntax and just write out the return values, comma-separated. Note: this technically returns a tuple.

许多答案提示您需要返回某种类型的集合,如字典或列表。您可以省略额外的语法,并写出返回值,逗号分隔。注意:这技术上返回一个元组。

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

gives:

给:

True
False

#4


46  

I vote for the dictionary.

我投票选那本词典。

I find that if I make a function that returns anything more than 2-3 variables I'll fold them up in a dictionary. Otherwise I tend to forget the order and content of what I'm returning.

我发现,如果我创建一个函数,它会返回任何超过2-3个变量,我将把它们折叠成字典。否则我就会忘记我要返回的东西的顺序和内容。

Also, introducing a 'special' structure makes your code more difficult to follow. (Someone else will have to search through the code to find out what it is)

此外,引入“特殊”结构会让代码更难遵循。(其他人必须通过代码来查找它是什么)

If your concerned about type look up, use descriptive dictionary keys, for example, 'x-values list'.

如果您关心类型查找,请使用描述性字典键,例如“x值列表”。

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }

#5


24  

Another option would be using generators:

另一种选择是使用发电机:

>>> def f(x):
        y0 = x + 1
        yield y0
        yield x * 3
        yield y0 ** 4


>>> a, b, c = f(5)
>>> a
6
>>> b
15
>>> c
1296

Although IMHO tuples are usually best, except in cases where the values being returned are candidates for encapsulation in a class.

虽然IMHO tuple通常是最好的,但是在返回的值是类中封装的候选者的情况除外。

#6


19  

>>> def func():
...    return [1,2,3]
...
>>> a,b,c = func()
>>> a
1
>>> b
2
>>> c
3

#7


17  

I prefer to use tuples whenever a tuple feels "natural"; coordinates are a typical example, where the separate objects can stand on their own, e.g. in one-axis only scaling calculations.

我喜欢在元组感觉“自然”的时候使用元组;坐标是一个典型的例子,在这个例子中,独立的对象可以独立存在,例如,在一个轴中,只有缩放计算。

I use dictionaries as a return value only when the grouped objects aren't always the same. Think optional email headers.

只有当被分组的对象不总是相同的时候,我才使用字典作为返回值。认为可选的电子邮件标题。

For the rest of the cases, where the grouped objects have inherent meaning inside the group or a fully-fledged object with its own methods is needed, I use a class.

对于其余的情况,需要使用类,其中的分组对象在组内具有内在的含义,或者有一个完全成熟的对象,需要自己的方法。

#8


16  

I prefer

我更喜欢

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }

it seems everything else is just extra code to do the same thing.

似乎其他的东西都只是额外的代码来做同样的事情。

#9


10  

Generally, the "specialized structure" actually IS a sensible current state of an object, with its own methods.

一般来说,“专门化结构”实际上是一个对象的合理的当前状态,有自己的方法。

class Some3SpaceThing(object):
  def __init__(self,x):
    self.g(x)
  def g(self,x):
    self.y0 = x + 1
    self.y1 = x * 3
    self.y2 = y0 ** y3

r = Some3SpaceThing( x )
r.y0
r.y1
r.y2

I like to find names for anonymous structures where possible. Meaningful names make things more clear.

我喜欢在可能的地方找到匿名结构的名字。有意义的名字会让事情变得更清晰。

#10


9  

+1 on S.Lott's suggestion of a named container class.

在S + 1。Lott对命名容器类的建议。

For python 2.6 and up, a named tuple provides a useful way of easily creating these container classes, and the results are "lightweight and require no more memory than regular tuples".

对于python 2.6和up,一个命名的tuple提供了一种很有用的方法来轻松创建这些容器类,并且结果是“轻量级的,并且不需要比常规元组更多的内存”。

#11


9  

Python's tuples, dicts, and objects offer the programmer a smooth tradeoff between formality and convenience for small data structures ("things"). For me, the choice of how to represent a thing is dictated mainly by how I'm going to use the structure. In C++, it's a common convention to use struct for data-only items and class for objects with methods, even though you can legally put methods on a struct; my habit is similar in Python, with dict and tuple in place of struct.

Python的元组、dicts和对象为编程人员提供了一种平滑的折衷方案,方便了小型数据结构(“things”)的形式和方便。对我来说,如何表示事物的选择主要取决于我如何使用这个结构。在c++中,虽然可以合法地将方法放在struct上,但是使用struct只针对有方法的对象的对象和类是一种常见的惯例。我的习惯在Python里是类似的,有命令和元组代替struct。

For coordinate sets, I'll use a tuple rather than a point class or a dict (and note that you can use a tuple as a dictionary key, so dicts make great sparse multidimensional arrays).

对于坐标集,我将使用tuple而不是一个point类或命令(注意,您可以使用tuple作为字典键,因此dicts可以生成非常稀疏的多维数组)。

If I'm going to be iterating over a list of things, I prefer unpacking tuples on the iteration:

如果我要在一个列表上进行迭代,我更喜欢在迭代过程中取消包装:

for score,id,name in scoreAllTheThings():
    if score > goodScoreThreshold:
        print "%6.3f #%6d %s"%(score,id,name)

...as the object version is more cluttered to read:

…因为对象的版本更杂乱:

for entry in scoreAllTheThings():
    if entry.score > goodScoreThreshold:
        print "%6.3f #%6d %s"%(entry.score,entry.id,entry.name)

...let alone the dict.

…更不用说关键字。

for entry in scoreAllTheThings():
    if entry['score'] > goodScoreThreshold:
        print "%6.3f #%6d %s"%(entry['score'],entry['id'],entry['name'])

If the thing is widely used, and you find yourself doing similar non-trivial operations on it in multiple places in the code, then it's usually worthwhile to make it a class object with appropriate methods.

如果这个东西被广泛使用,并且您发现自己在代码中的多个位置上执行类似的非平凡操作,那么通常值得用适当的方法使它成为类对象。

Finally, if I'm going to be exchanging data with non-Python system components, I'll most often keep them in a dict because that's best suited to JSON serialization.

最后,如果我要用非python系统组件交换数据,我通常会将它们保存在字典中,因为这最适合于JSON序列化。

#12


1  

In languages like Python, I would usually use a dictionary as it involves less overhead than creating a new class.

在Python这样的语言中,我通常使用字典,因为它比创建一个新类的开销更少。

However, if I find myself constantly returning the same set of variables, then that probably involves a new class that I'll factor out.

但是,如果我发现自己不断地返回相同的变量集,那么可能涉及到一个新的类,我将把它提出来。

#13


0  

I would use a dict to pass and return values from a function:

我将使用一条命令从函数中传递和返回值:

Use variable form as defined in form.

使用形式定义的变量形式。

form = {
    'level': 0,
    'points': 0,
    'game': {
        'name': ''
    }
}


def test(form):
    form['game']['name'] = 'My game!'
    form['level'] = 2

    return form

>>> print(test(form))
{u'game': {u'name': u'My game!'}, u'points': 0, u'level': 2}

This is the most efficient way for me and for processing unit.

这是我和处理单位最有效的方式。

You have to pass just one pointer in and return just one pointer out.

你只需要传递一个指针,然后返回一个指针。

You do not have to change functions' (thousands of them) arguments whenever you make a change in your code.

当您在代码中进行更改时,您不需要更改函数(数千个)的参数。

#1


464  

Named tuples were added in 2.6 for this purpose. Also see os.stat for a similar builtin example.

为此,在2.6中添加了命名元组。也看到操作系统。这是一个类似的内置例子。

>>> 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

#2


151  

For small projects I find it easiest to work with tuples. When that gets too hard to manage (and not before) I start grouping things into logical structures, however I think your suggested use of dictionaries and ReturnValue objects is wrong (or too simplistic).

对于小型项目,我发现使用元组是最容易的。当这变得很难管理(而不是以前)时,我开始将事情分组到逻辑结构中,但是我认为您建议使用字典和ReturnValue对象是错误的(或者过于简单)。

Returning a dictionary with keys y0, y1, y2 etc doesn't offer any advantage over tuples. Returning a ReturnValue instance with properties .y0 .y1 .y2 etc doesn't offer any advantage over tuples either. You need to start naming things if you want to get anywhere, and you can do that using tuples anyway:

返回一个带键y0、y1、y2等的字典并不比元组有任何优势。返回具有属性的ReturnValue实例。y0 .y1 .y2等也没有提供任何优于元组的优点。你需要开始命名东西,如果你想要得到任何地方,你可以使用元组来做:

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

IMHO, the only good technique beyond tuples is to return real objects with proper methods and properties, like you get from re.match() or open(file).

除了tuple之外,唯一的好方法是使用正确的方法和属性返回真正的对象,就像从re.match()或open(文件)中得到的一样。

#3


85  

A lot of the answers suggest you need to return a collection of some sort, like a dictionary or a list. You could leave off the extra syntax and just write out the return values, comma-separated. Note: this technically returns a tuple.

许多答案提示您需要返回某种类型的集合,如字典或列表。您可以省略额外的语法,并写出返回值,逗号分隔。注意:这技术上返回一个元组。

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

gives:

给:

True
False

#4


46  

I vote for the dictionary.

我投票选那本词典。

I find that if I make a function that returns anything more than 2-3 variables I'll fold them up in a dictionary. Otherwise I tend to forget the order and content of what I'm returning.

我发现,如果我创建一个函数,它会返回任何超过2-3个变量,我将把它们折叠成字典。否则我就会忘记我要返回的东西的顺序和内容。

Also, introducing a 'special' structure makes your code more difficult to follow. (Someone else will have to search through the code to find out what it is)

此外,引入“特殊”结构会让代码更难遵循。(其他人必须通过代码来查找它是什么)

If your concerned about type look up, use descriptive dictionary keys, for example, 'x-values list'.

如果您关心类型查找,请使用描述性字典键,例如“x值列表”。

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }

#5


24  

Another option would be using generators:

另一种选择是使用发电机:

>>> def f(x):
        y0 = x + 1
        yield y0
        yield x * 3
        yield y0 ** 4


>>> a, b, c = f(5)
>>> a
6
>>> b
15
>>> c
1296

Although IMHO tuples are usually best, except in cases where the values being returned are candidates for encapsulation in a class.

虽然IMHO tuple通常是最好的,但是在返回的值是类中封装的候选者的情况除外。

#6


19  

>>> def func():
...    return [1,2,3]
...
>>> a,b,c = func()
>>> a
1
>>> b
2
>>> c
3

#7


17  

I prefer to use tuples whenever a tuple feels "natural"; coordinates are a typical example, where the separate objects can stand on their own, e.g. in one-axis only scaling calculations.

我喜欢在元组感觉“自然”的时候使用元组;坐标是一个典型的例子,在这个例子中,独立的对象可以独立存在,例如,在一个轴中,只有缩放计算。

I use dictionaries as a return value only when the grouped objects aren't always the same. Think optional email headers.

只有当被分组的对象不总是相同的时候,我才使用字典作为返回值。认为可选的电子邮件标题。

For the rest of the cases, where the grouped objects have inherent meaning inside the group or a fully-fledged object with its own methods is needed, I use a class.

对于其余的情况,需要使用类,其中的分组对象在组内具有内在的含义,或者有一个完全成熟的对象,需要自己的方法。

#8


16  

I prefer

我更喜欢

def g(x):
  y0 = x + 1
  y1 = x * 3
  y2 = y0 ** y3
  return {'y0':y0, 'y1':y1 ,'y2':y2 }

it seems everything else is just extra code to do the same thing.

似乎其他的东西都只是额外的代码来做同样的事情。

#9


10  

Generally, the "specialized structure" actually IS a sensible current state of an object, with its own methods.

一般来说,“专门化结构”实际上是一个对象的合理的当前状态,有自己的方法。

class Some3SpaceThing(object):
  def __init__(self,x):
    self.g(x)
  def g(self,x):
    self.y0 = x + 1
    self.y1 = x * 3
    self.y2 = y0 ** y3

r = Some3SpaceThing( x )
r.y0
r.y1
r.y2

I like to find names for anonymous structures where possible. Meaningful names make things more clear.

我喜欢在可能的地方找到匿名结构的名字。有意义的名字会让事情变得更清晰。

#10


9  

+1 on S.Lott's suggestion of a named container class.

在S + 1。Lott对命名容器类的建议。

For python 2.6 and up, a named tuple provides a useful way of easily creating these container classes, and the results are "lightweight and require no more memory than regular tuples".

对于python 2.6和up,一个命名的tuple提供了一种很有用的方法来轻松创建这些容器类,并且结果是“轻量级的,并且不需要比常规元组更多的内存”。

#11


9  

Python's tuples, dicts, and objects offer the programmer a smooth tradeoff between formality and convenience for small data structures ("things"). For me, the choice of how to represent a thing is dictated mainly by how I'm going to use the structure. In C++, it's a common convention to use struct for data-only items and class for objects with methods, even though you can legally put methods on a struct; my habit is similar in Python, with dict and tuple in place of struct.

Python的元组、dicts和对象为编程人员提供了一种平滑的折衷方案,方便了小型数据结构(“things”)的形式和方便。对我来说,如何表示事物的选择主要取决于我如何使用这个结构。在c++中,虽然可以合法地将方法放在struct上,但是使用struct只针对有方法的对象的对象和类是一种常见的惯例。我的习惯在Python里是类似的,有命令和元组代替struct。

For coordinate sets, I'll use a tuple rather than a point class or a dict (and note that you can use a tuple as a dictionary key, so dicts make great sparse multidimensional arrays).

对于坐标集,我将使用tuple而不是一个point类或命令(注意,您可以使用tuple作为字典键,因此dicts可以生成非常稀疏的多维数组)。

If I'm going to be iterating over a list of things, I prefer unpacking tuples on the iteration:

如果我要在一个列表上进行迭代,我更喜欢在迭代过程中取消包装:

for score,id,name in scoreAllTheThings():
    if score > goodScoreThreshold:
        print "%6.3f #%6d %s"%(score,id,name)

...as the object version is more cluttered to read:

…因为对象的版本更杂乱:

for entry in scoreAllTheThings():
    if entry.score > goodScoreThreshold:
        print "%6.3f #%6d %s"%(entry.score,entry.id,entry.name)

...let alone the dict.

…更不用说关键字。

for entry in scoreAllTheThings():
    if entry['score'] > goodScoreThreshold:
        print "%6.3f #%6d %s"%(entry['score'],entry['id'],entry['name'])

If the thing is widely used, and you find yourself doing similar non-trivial operations on it in multiple places in the code, then it's usually worthwhile to make it a class object with appropriate methods.

如果这个东西被广泛使用,并且您发现自己在代码中的多个位置上执行类似的非平凡操作,那么通常值得用适当的方法使它成为类对象。

Finally, if I'm going to be exchanging data with non-Python system components, I'll most often keep them in a dict because that's best suited to JSON serialization.

最后,如果我要用非python系统组件交换数据,我通常会将它们保存在字典中,因为这最适合于JSON序列化。

#12


1  

In languages like Python, I would usually use a dictionary as it involves less overhead than creating a new class.

在Python这样的语言中,我通常使用字典,因为它比创建一个新类的开销更少。

However, if I find myself constantly returning the same set of variables, then that probably involves a new class that I'll factor out.

但是,如果我发现自己不断地返回相同的变量集,那么可能涉及到一个新的类,我将把它提出来。

#13


0  

I would use a dict to pass and return values from a function:

我将使用一条命令从函数中传递和返回值:

Use variable form as defined in form.

使用形式定义的变量形式。

form = {
    'level': 0,
    'points': 0,
    'game': {
        'name': ''
    }
}


def test(form):
    form['game']['name'] = 'My game!'
    form['level'] = 2

    return form

>>> print(test(form))
{u'game': {u'name': u'My game!'}, u'points': 0, u'level': 2}

This is the most efficient way for me and for processing unit.

这是我和处理单位最有效的方式。

You have to pass just one pointer in and return just one pointer out.

你只需要传递一个指针,然后返回一个指针。

You do not have to change functions' (thousands of them) arguments whenever you make a change in your code.

当您在代码中进行更改时,您不需要更改函数(数千个)的参数。