1. ホーム
  2. python

[解決済み] Python3のlambdaの自動タプルアンパッキングに相当するものは何ですか?

2022-08-14 11:10:44

質問

以下の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)

これは非常に醜い。ラムダが関数なら

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

Python3でこの機能を削除すると、コードは醜い方法(マジックインデックス)を使うか、不要な関数(最も面倒なのは、これらの不要な関数の良い名前を考えること)を作らなければならなくなります。

私は、この機能は少なくともラムダだけに戻されるべきだと思います。良い代替案はないでしょうか?


更新しました。 私は回答にあるアイデアを拡張して、以下のヘルパーを使用しています。

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

どのように解決するのですか?

いいえ、他に方法はありません。あなたはそれをすべてカバーしました。方法としては、この問題を Python ideas メーリングリスト で提起することですが、そこで何らかの牽引力を得るために多くの議論をする覚悟が必要です。

実は、quot;not is no way out"と言わないために、第三の方法として、パラメータを展開するためだけにラムダ呼び出しのもう一つのレベルを実装することができます - しかしそれは同時に、あなたの二つの提案よりも非効率で読みにくいものになるでしょう。

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


Python 3.8 アップデート

Python 3.8のリリース以降、PEP 572 - 代入式 - がツールとして利用できるようになりました。

そこで、ラムダ内で複数の式を実行するトリックを使えば - 私は通常、タプルを作成してその最後の構成要素を返すだけにしています - 次のようにすることが可能です。

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

この種のコードは、完全な関数を持つよりも読みやすく、実用的であることはめったにないことを心に留めておく必要があります。それでも、可能な使い方はあります - もし、これを操作する様々なワンライナーがあれば point を操作する様々なワンライナーがある場合、それは namedtuple そして,代入式を使って,入力されるシーケンスを名前付きタプルに効果的に "キャスト" してください.

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