Python3中好的自动元组解包lambda相当于什么?

2024-03-28 14:56:32 发布

您现在位置: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中删除这个特性会迫使代码要么采用丑陋的方式(使用魔法索引)要么创建不必要的函数(最麻烦的部分是为这些不必要的函数想出好名字)

我认为这个特性至少应该单独添加回lambdas。有好的选择吗?


更新:我正在使用下面的助手扩展答案中的想法

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

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

更新2:的更干净版本star

import functools

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

Tags: lambdakey函数代码inreturndefargs
3条回答

不,没有别的办法了。你把一切都掩盖了。方法是在Python ideas mailing list上提出这个问题,但要准备好在那里争论很多以获得一些吸引力。

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

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

更新Python 3.8

到目前为止,Python3.8Alpha1已经可用,并且实现了PEP572-赋值表达式。

因此,如果在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]

我不知道Python 2参数解包行为有什么好的通用替代方法。以下是一些在某些情况下可能有用的建议:

  • 如果无法想到名称,请使用关键字参数的名称:

    def key(p): # more specific name would be better
        x, y = p
        return x**2 + y**3
    
    result = min(points, key=key)
    
  • 如果列表在多个位置使用,则可以看到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)
    

根据http://www.python.org/dev/peps/pep-3113/,元组解包已经消失,并且2to3将像这样翻译它们:

As tuple parameters are used by lambdas because of the single expression limitation, they must also be supported. This is done by having the expected sequence argument bound to a single parameter and then indexing on that parameter:

lambda (x, y): x + y

will be translated into:

lambda x_y: x_y[0] + x_y[1]

这与您的实现非常相似。

相关问题 更多 >