如何在3.x中使用lambda参数模拟2.x的元组解包?

11 浏览
0 Comments

如何在3.x中使用lambda参数模拟2.x的元组解包?

在Python 2中,我可以这样写:

In [5]: points = [ (1,2), (2,3)]
In [6]: min(points, key=lambda (x, y): (x*x + y*y))
Out[6]: (1, 2)

但是在3.x版本中不支持这样写:

  File "", line 1
    min(points, key=lambda (x, y): (x*x + y*y))
                           ^
SyntaxError: invalid syntax

直接的解决方法是显式地索引传入的元组:

>>> min(points, key=lambda p: p[0]*p[0] + p[1]*p[1])
(1, 2)

这样做很丑陋。如果lambda是一个函数,我可以这样做:

def some_name_to_think_of(p):
    x, y = p
    return x*x + y*y

但是因为lambda只支持单个表达式,所以无法将"x, y = p"部分放入其中。

还有其他方法可以解决这个限制吗?

0
0 Comments

在Python 2中,元组解包(tuple unpacking)的行为可以用于将元组中的元素分别赋值给多个变量。然而,在Python 3中,这种行为已经被移除了。因此,有人提出了一个问题,即如何在Python 3中模拟Python 2中的元组解包行为,以便在lambda参数中使用。

问题的原因是Python 2中的元组解包行为在Python 3中被移除了,导致无法直接在lambda参数中使用。为了解决这个问题,有几个解决方法可以考虑。

首先,可以使用关键字参数的名称作为变量名,来模拟元组解包的行为。例如,在一个函数中,可以将参数p作为元组,并将其解包为变量x和y。然后,可以使用这些变量进行计算。以下是一个示例代码:

def key(p):
    x, y = p
    return x**2 + y**3
result = min(points, key=key)

另一个解决方法是使用namedtuple,它可以使代码更易读。如果列表在多个地方使用,可以将其转换为namedtuple类型的对象。以下是一个示例代码:

from collections import namedtuple
from itertools import starmap
points = [ (1,2), (2,3)]
Point = namedtuple('Point', 'x y')
points = list(starmap(Point, points))
result = min(points, key=lambda p: p.x**2 + p.y**3)

以上两种方法中,使用namedtuple是最好的解决方法。它不仅可以保留lambda表达式,而且我发现namedtuple版本更易读,因为lambda (x, y):lambda x, y:之间的区别一眼就能看出来。

总结起来,Python 2中的元组解包行为在Python 3中被移除,导致无法直接在lambda参数中使用。为了解决这个问题,可以使用关键字参数的名称作为变量名,或者使用namedtuple来模拟元组解包行为。其中,使用namedtuple是最佳解决方法。

0
0 Comments

在Python 3.x中,元组解包(tuple unpacking)的功能被移除了。根据PEP 3113的规定,使用2to3工具进行代码转换时,元组解包的部分会被转换为索引定位的方式,以支持lambda函数的参数解包操作。

具体来说,PEP 3113指出,由于lambda函数只能接受单个表达式作为参数,所以需要对元组参数进行特殊处理。在转换过程中,原本使用元组参数的lambda函数将会被转换为将期望的序列参数绑定到单个参数上,并通过索引操作来获取元素的方式。例如,原本的lambda函数lambda (x, y): x + y会被转换为lambda x_y: x_y[0] + x_y[1]

这种转换方式与原来的实现相当相似,好在在for循环或列表推导等其他地方并没有移除元组解包的功能。

总结起来,Python 3.x中移除了元组解包的功能,为了兼容之前使用元组参数的lambda函数,PEP 3113规定了使用索引定位的方式来模拟旧版本中的元组解包功能。这种转换方式可以确保之前的代码在Python 3.x中能够正常运行。

0
0 Comments

问题的出现原因:

Python 3.x中的lambda函数无法像Python 2.x那样对元组进行解包操作,导致无法使用lambda函数进行元组解包的模拟。

解决方法:

1. 在Python ideas邮件列表上提出这个问题,并准备在那里进行大量辩论以获得一些关注。

2. 另一种方法是在lambda调用中实现一个额外的级别来展开参数,但这比起前两种方法更加低效和难以阅读。

min(points, key=lambda p: (lambda x,y: (x*x + y*y))(*p))

Python 3.8更新:

自从Python 3.8发布以来,PEP 572 - 赋值表达式 - 已经作为一种工具得到了应用。

因此,如果使用一个在lambda内部执行多个表达式的技巧 - 我通常通过创建一个元组并返回其中的最后一个组件来实现 - 可以进行如下操作:

>>> a = lambda p:(x:=p[0], y:=p[1], x ** 2 + y ** 2)[-1]
>>> a((3,4))
25

需要记住的是,这种代码很少比拥有一个完整函数更具可读性或实用性。然而,还是存在一些可能的用途 - 如果有多个一行代码的操作将在这个点上进行操作,那么使用namedtuple进行“强制转换”传入的序列可能是值得的:

>>> from collections import namedtuple
>>> point = namedtuple("point", "x y")
>>> b = lambda s: (p:=point(*s), p.x ** 2 + p.y ** 2)[-1]

当然,我忘了提到的“一种明显”的方法是实际上使用def关键字花费三行函数实现,这也在问题下面的some_name_to_think-of中提到了。

这个答案仍然有一些访问者 - 使用PEP 572的实现,应该有一种方法在lambda表达式中创建变量,就像这样:key = lambda p: (x:=p[0], y:=p[1], x ** 2 + y ** 2)[-1]

赋值表达式!!我对它们能够实现感到(愉快)惊讶。

我喜欢这种使用C语言的逗号运算符的方法。:D [a, b, c][-1]

所以...我们还不能像x,y := p这样做吗?

0