一尘不染

在lambda中自动元组解包的python3等效项是什么?

python

考虑以下python2代码

In [5]: points = [ (1,2), (2,3)]

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

python3不支持此功能,我必须执行以下操作:

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

在python3中删除此功能会强制代码执行丑陋的方式(使用魔术索引)或创建不必要的功能(最麻烦的部分是为这些不必要的功能想到好名字)

我认为该功能至少应单独添加回lambda。有没有好的选择?


更新: 我正在使用以下帮助程序扩展答案中的想法

def star(f):
  return lambda args: f(*args)

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

Update2: 的清洁版本star

import functools

def star(f):
    @functools.wraps(f):
    def f_inner(args):
        return f(*args)
    return f_inner

阅读 241

收藏
2021-01-20

共1个答案

一尘不染

不,没有其他办法。您覆盖了所有内容。可行的方法是在Python想法邮件列表中提出此问题,但要准备在那儿争论很多以获得更多关注。

实际上,只是不说“没有出路”,第三种方法可能是实现一个更高级别的lambda调用,只是为了展开参数-但这将比您的两个建议效率更高,更难以阅读:

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

更新Python 3.8

到目前为止,Python 3.8 alpha1已可用,并且已实现PEP 572赋值表达式。

因此,如果使用技巧在lambda内执行多个表达式-我通常通过创建一个元组并仅返回它的最后一个组件来做到这一点,可以这样做:

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

应该记住,与具有完整功能相比,这种代码很少会更具可读性或实用性。仍然有可能的用途-
如果有各种各样的单行代码可以对此进行操作point,则值得拥有一个namedtuple,并使用赋值表达式将输入序列有效地“投射”到namedtuple:

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