忽略 Python 的多返回值

393

假设我有一个Python函数,它返回一个元组中的多个值:

def func():
    return 1, 2

除了仅将其分配给临时变量外,是否有一种好的方法来忽略其中一个结果?例如,如果我只对第一个值感兴趣,是否有比这更好的方法:

x, temp = func()

3
我也对这个产生了好奇,因为Matlab有类似的概念,称为“忽略函数输出”,使用符号~来表示忽略特定的返回变量。请问你需要翻译什么内容? - jxramos
5
你选择了错误的答案作为解决方案。 - AGP
12个回答

757

您可以使用 x = func()[0] 来返回第一个值,x = func()[1] 来返回第二个值,依此类推。

如果您想一次获取多个值,请使用类似 x,y = func()[2:4] 的方式。


109
这应该是被接受的答案。如果您只想要一些返回值,您也可以使用 func()[2:4] 等类似方法。 - endolith
14
它不会多次调用函数:
def test(): ... print "这里" ... return 1,2,3 ... a,b = test()[:2] 这里 [编辑:对不起,该代码没有出现,显然在评论中只能得到一行。对于不熟悉的人,">>>"和"..."是Python shell中新行的开头]
- teeks99
51
@TylerLong: 我认为使用 _, _, _, _, _, _, _, _, _, _, _, _, _, a, _, _, _, _, _, _, _, _, _, _, _, b, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, c, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, d, _, _, _, _, _, _, _, _, e, _ = func() 没有调用函数多次来得清晰,但这只是我的意见。如果您的函数返回这么多项目,则我认为使用numpy会更好:a, b, c, d, e = func()[[13, 25, 58, 89, 98]] - endolith
37
我认为这个做法更好,不需要依赖NumPy,并且不需要多次调用func()函数:result = func() a = result[13] b = result[25] ... - Tyler Liu
5
当你想忽略其中一个或几个值时,这种写法不太好,例如 x, __, y = func() - ndemou
显示剩余13条评论

345

常见的惯例是使用 "_" 作为要忽略的元组元素的变量名。例如:

def f():
    return 1, 2, 3

_, _, x = f()

105
在将 gettext 功能添加到别人的代码中时(该代码定义了一个名为“_”的函数),这种“惯例”很糟糕,因此应该被禁止。 - nosklo
42
好观点——尽管gettext坚持安装一个名为“_”的函数是否明智还有争议。就我个人而言,我觉得这有点难看。不管怎样,“_”作为一个临时变量的使用是广泛的。 - Brian Clapper
35
在IPython中,"_(下划线)"表示上一次的输出。我永远不会给它赋值。 - endolith
26
好的,我没有注意到那个“我” - 感谢提供参考。在我看来,你不能期望别人不使用一个变量,只因为一个Python应用程序为其定义了自己神奇的用途。 - Draemon
10
像PyDev这样的一些集成开发环境会对此发出警告,因为你有未使用的变量。 - teeks99
显示剩余15条评论

146
如果您正在使用Python 3,您可以在变量前(赋值语句的左侧)使用星号,使其成为解包中的列表。
# Example 1: a is 1 and b is [2, 3]

a, *b = [1, 2, 3]

# Example 2: a is 1, b is [2, 3], and c is 4

a, *b, c = [1, 2, 3, 4]

# Example 3: b is [1, 2] and c is 3

*b, c = [1, 2, 3]       

# Example 4: a is 1 and b is []

a, *b = [1]

33
你也可以使用a, *_ = f()来忽略f()返回的任意数量的值,只保留第一个值赋给变量a - THN

29

通常的做法是使用虚拟变量_(下划线),就像许多人在此之前指出的那样。

然而,为了避免与该变量名的其他用途发生冲突(参见回答),最好使用双下划线__代替作为丢弃变量,正如ncoghlan所指出的那样。例如:

x, __ = func()

5
这个想法不错。但是,'_'会在命名空间中声明变量。而''则不声明,除非像上面的赋值语句左侧明确使用(例如:a,_,_ = 1,8,9)。在此之前,它会存储执行的最后一个语句的结果,如果您想要捕获它,通常需要使用一个变量来存储该值。这就是为什么建议使用''来捕获无用的值。''的值很快会被另一个语句覆盖。对于“__”情况,值将保留,直到GC将其清除。 - Archit

23

请记住,当您返回多个项时,实际上您返回的是一个元组。因此,您可以像这样做:

def func():
    return 1, 2

print func()[0] # prints 1
print func()[1] # prints 2

有用于语法的。这种方法的问题在于需要多次调用函数。对于如此微不足道的函数来说,这并不是什么大问题。但是,在更复杂的函数中,这可能是不可取的。很高兴知道有许多方法可以解决这个问题... - jvriesem

22
最好的解决方案可能是给事物命名,而不是返回无意义的元组(除非返回项的顺序有一些逻辑)。例如,您可以使用一个字典:
def func():
    return {'lat': 1, 'lng': 2}
    
latitude = func()['lat']

你甚至可以使用namedtuple,如果你想要添加关于返回值的额外信息(它不仅仅是一个字典,而是一对坐标):
from collections import namedtuple 

Coordinates = namedtuple('Coordinates', ['lat', 'lng'])

def func():
    return Coordinates(lat=1, lng=2)

latitude = func().lat

如果字典/元组中的对象之间有强烈的关联,那么为其定义一个类可能是一个好主意。这样你还可以定义更复杂的操作。一个自然的问题是:我应该在什么时候在Python中使用类?

最近版本的Python(≥ 3.7)具有dataclasses,你可以使用它来用非常少的代码定义类:

from dataclasses import dataclass

@dataclass
class Coordinates:
    lat: float = 0
    lng: float = 0

def func():
    return Coordinates(lat=1, lng=2)

latitude = func().lat

dataclass相较于namedtuple的主要优势在于更容易扩展,但还存在其他区别。请注意,默认情况下,dataclass是可变的,但您可以使用@dataclass(frozen=True)代替@dataclass以强制使其成为不可变。

这里有一个视频可能会帮助您选择适合您使用情况的正确数据类。还有一个关于attrs vs. dataclass的视频,它揭示了一些关于为什么attrs可能很有意思的有趣细节。


2
这是唯一一个深入探讨此问题的答案。如果您试图选择函数的元组输出之一,则它们可能不应该在元组中。元组用于以有序方式“配对”的事物。在 OP 的情况下,它们(可能)是“质量上不同”的输出,并且应该以某种方式真正命名。当没有自然排序时,要求读者理解第一个和第二个输出所指的内容是麻烦的根源。 - Sanjay Manohar

19

三个简单选择。

显而易见的。

x, _ = func()

x, junk = func()

骇人听闻的

x = func()[0]

有一种方法可以使用装饰器实现这一点。

def val0( aFunc ):
    def pick0( *args, **kw ):
        return aFunc(*args,**kw)[0]
    return pick0

func0= val0(func)

6
我更喜欢使用“_”变量。很明显你正在忽略一个值。 - Claudiu
26
你的例子是相反的。x, _ = func() 非常丑陋,而 x = func()[0] 则很明显。赋值给变量后却没有使用它?该函数返回一个元组,像处理元组一样索引即可。 - endolith
9
在模式匹配语言中,Python从中继承了这种模式。'显而易见'的方法确实是显而易见、不令人讨厌和规范的。但是,在这些语言中,通配符是一种支持的语言特性,而在Python中它是一个实际变量并且会被绑定,这是有点令人不舒服的。 - Joe
5
对于列表处理语言,Python 就是从中派生出来的 ;)。诸如 a[0]a[:](列表拷贝)、a[::2](每隔两个元素)以及 a[i:] + a[:i](旋转列表)等列表访问方法确实也很明显并且经典。 - cod3monk3y

6
这对我来说似乎是最好的选择:
val1, val2, ignored1, ignored2 = some_function()

它既不晦涩难懂,也不难看(不像 func()[index] 方法),而且能清楚地表达你的意图。

1
这个看起来稍微好一点: val1, val2, *ignored = some_function() - vineet gundecha
1
这个看起来稍微好一点: val1, val2, *ignored = some_function() - undefined

5

这不是对问题的直接回答,而是回答了这个问题:“如何从许多可能的选项中选择特定的函数输出?”。

如果您能够编写该函数(即它不在您无法修改的库中),则添加一个输入参数,指示您想要从函数中获取什么。将其作为命名参数添加,并设置默认值,以便在“常见情况”下甚至不需要指定它。

    def fancy_function( arg1, arg2, return_type=1 ):
        ret_val = None
        if( 1 == return_type ):
            ret_val = arg1 + arg2
        elif( 2 == return_type ):
            ret_val = [ arg1, arg2, arg1 * arg2 ]
        else:
            ret_val = ( arg1, arg2, arg1 + arg2, arg1 * arg2 ) 
        return( ret_val )

这种方法可以提前为所需输出提供“高级警告”。因此,它可以跳过不必要的处理,并且只执行获取所需输出所必需的工作。另外,由于Python采用动态类型,返回类型可以发生变化。请注意,示例返回标量、列表或元组...任何你想要的!


5
如果您经常使用这个函数但总是丢弃第二个参数,我认为使用lambda创建一个没有第二个返回值的函数别名会更加简洁。
def func():
    return 1, 2

func_ = lambda: func()[0] 

func_()  # Prints 1 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接