Skip to content
Advertisement

How can I simulate 2.x’s tuple unpacking for lambda parameters, using 3.x?

In Python 2, I can write:

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

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

But that is not supported in 3.x:

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

The straightforward workaround is to index explicitly into the tuple that was passed:

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

This is very ugly. If the lambda were a function, I could do

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

But because the lambda only supports a single expression, it’s not possible to put the x, y = p part into it.

How else can I work around this limitation?

Advertisement

Answer

No, there is no other way. You covered it all. The way to go would be to raise this issue on the Python ideas mailing list, but be prepared to argue a lot over there to gain some traction.

Actually, just not to say “there is no way out”, a third way could be to implement one more level of lambda calling just to unfold the parameters – but that would be at once more inefficient and harder to read than your two suggestions:

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

Python 3.8 update

Since the release of Python 3.8, PEP 572 — assignment expressions — have been available as a tool.

So, if one uses a trick to execute multiple expressions inside a lambda – I usually do that by creating a tuple and just returning the last component of it, it is possible to do the following:

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

One should keep in mind that this kind of code will seldom be more readable or practical than having a full function. Still, there are possible uses – if there are various one-liners that would operate on this point, it could be worth to have a namedtuple, and use the assignment expression to effectively “cast” the incoming sequence to the namedtuple:

>>> from collections import namedtuple
>>> point = namedtuple("point", "x y")
>>> b = lambda s: (p:=point(*s), p.x ** 2 + p.y ** 2)[-1]
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement