Pythonラムダが役立つのはなぜですか?[閉まっている]


929

私はPythonラムダを理解しようとしています。ラムダは、現実には忘れておくべき「興味深い」言語アイテムの1つですか?

私はそれが必要になるかもしれないいくつかのエッジケースがあると確信していますが、それが曖昧であること、将来のリリースで再定義される可能性(私のさまざまな定義に基づく私の仮定)、およびコーディングの明快さの低下-それがあれば避けられる?

これは、C型のオーバーフロー(バッファオーバーフロー)を思い出します。つまり、最上位の変数をポイントし、他のフィールド値を設定するためにオーバーロードしています。それは一種の技術者のショーマンシップのように感じますが、メンテナンスコーダーの悪夢です。


261
+1良い質問-悪い仮定(ラムダの曖昧さ)=)プログラミング手法を判断しないようにしてください。それらを評価し、メンタルツールキットに追加します。それらが気に入らない場合は使用せず、宗教的にならずに論理的に話し合う準備をしてください。
Kieveli

41
Haskellルール!ラムダ関数は、表現力と抽象力を提供します。
ジョナサンバルベロ2010

11
@JALは言うまでもなくLISPです...
ApproachingDarknessFish

8
@ApproachingDarknessFish「ああ、それはあなたの父親の括弧です。より文明的な時代のより文明的な武器です。」-Obi Lisp Kenobi
Fields

回答:


1009

ラムダ関数について話していますか?お気に入り

lambda x: x**2 + 2*x - 5

それらは実際には非常に便利です。Pythonは、関数型プログラミングと呼ばれるプログラミングスタイルをサポートしています。関数型プログラミングでは、関数を他の関数に渡して何かを実行できます。例:

mult3 = filter(lambda x: x % 3 == 0, [1, 2, 3, 4, 5, 6, 7, 8, 9])

に設定mult3[3, 6, 9]ます。元のリストの3の倍数の要素です。これは、

def filterfunc(x):
    return x % 3 == 0
mult3 = filter(filterfunc, [1, 2, 3, 4, 5, 6, 7, 8, 9])

もちろん、この特定のケースでは、リスト内包と同じことを行うことができます。

mult3 = [x for x in [1, 2, 3, 4, 5, 6, 7, 8, 9] if x % 3 == 0]

(またはとしてもrange(3,10,3))、しかし、リスト内包表記を使用できず、ラムダ関数が何かを書き込むための最短の方法である、他の多くのより洗練された使用例があります。

  • 別の関数から関数を返す

    >>> def transform(n):
    ...     return lambda x: x + n
    ...
    >>> f = transform(3)
    >>> f(4)
    7
    

    これは、Pythonのデコレータなどの関数ラッパーを作成するためによく使用されます。

  • 反復可能なシーケンスの要素を reduce()

    >>> reduce(lambda a, b: '{}, {}'.format(a, b), [1, 2, 3, 4, 5, 6, 7, 8, 9])
    '1, 2, 3, 4, 5, 6, 7, 8, 9'
    
  • 代替キーによる並べ替え

    >>> sorted([1, 2, 3, 4, 5, 6, 7, 8, 9], key=lambda x: abs(5-x))
    [5, 4, 6, 3, 7, 2, 8, 1, 9]
    

私はラムダ関数を定期的に使用しています。慣れるまでに少し時間がかかりましたが、やがて言語の非常に貴重な部分であることを理解するようになりました。


26
非常に理解しやすい例が大好きです。しかし、還元部分については。この機能を実装する必要がある場合。私はそうするでしょう','.join(str(x) for x in [1,2,3,4,5,6,7,8,9])
etlds

3
ところで、これをPython3で実行する場合は、フィルター結果のリストを呼び出して実際の値を確認する必要があります。また、functoolsから
Gerard

上記の「関数型プログラミング」の定義について確信がありますか?それは私を少し混乱させました。
stdout

3
重要な点は、lambda関数は匿名にすることができるということです(すべての例のように)。lambda関数を何かに割り当てている場合、それは間違っています。def代わりに使用する必要があります
Chris_Rands

1
@zgulserこれは定義ではなく、関数型プログラミングで実行できることについての単なる説明です。
David Z

377

lambdaと言うのは単なる派手な方法ですfunction。その名前以外に、曖昧で威圧的または不可解なものは何もありません。次の行を読んだときは、次のように置き換えlambdafunctionください。

>>> f = lambda x: x + 1
>>> f(3)
4

の関数を定義するだけですx。のような他のいくつかの言語Rはそれを明示的に言っています:

> f = function(x) { x + 1 }
> f(3)
4

分かりますか?これは、プログラミングで行う最も自然なことの1つです。


36
これは、非プログラミングの背景(つまり、正確な科学)の出身者にとってlambda 非常にわかりやすい説明です。ありがとう!
ガブリエル

10
レイモンドヘッティンガーは彼の講演の1つで名前を嘆き、「lambda」の代わりに「make function」と名前を付けることですべての混乱を回避できたはずだと述べました。:-)
ankush981 2016

10
頭の中で置き換えlambdafunction最後の表現の前に追加return
CiprianTomoiagă'28

4
@AaronMcMillinお試しくださいtype(lambda x: 3)lambda式とdefステートメントの両方がfunctionオブジェクトを生成します。それが唯一の構文でlambda制限することを表現され、それが生成することができますインスタンス。
chepner

6
@AaronMcMillinあなたは私のポイントを逃しています。あなたが定義することはできませんからといって、すべての関数lambda式をした結果という意味ではありませんlambda式はない機能。
chepner

107

2行の要約:

  1. 閉鎖:非常に便利です。それらを学び、使用し、愛してください。
  2. Pythonのlambdaキーワード:不要、時々有用。リモートで複雑なことをしている場合は、それを片付けて実際の関数を定義してください。

72

ラムダは、高次関数を扱う非常に重要な抽象化メカニズムの一部です。その価値を正しく理解するには、AbelsonとSussmanからの質の高いレッスンを見て、SICPの本を読んでください。

これらは現代のソフトウェアビジネスに関連する問題であり、ますます人気が高まっています。


1
ラムダ式は、他の言語(C#など)でも人気が高まっています。彼らはどこにも行きません。クロージャーについて理解することは、ラムダを理解するための有用な練習になります。クロージャーは、jQueryのようなフレームワークで多くのコーディングの魔法を可能にします。
Dan Esparza、

3
lambdaとファーストクラスの機能を混同しないでください。Pythonのlambdaステートメントは非常に限られていますが、完全にファーストクラスの関数です。唯一の違いは、渡したい関数に名前を付けなければならないことです。
Gareth Latty 2014年

59

ラムダはGUIプログラミングで非常に役立ちます。たとえば、ボタンのグループを作成していて、ボタンごとに固有のコールバックではなく、パラメータ化された単一のコールバックを使用したいとします。Lambdaを使用すると、簡単にそれを実現できます。

for value in ["one","two","three"]:
    b = tk.Button(label=value, command=lambda arg=value: my_callback(arg))
    b.pack()

(注:この質問は特にについて尋ねていlambdaますが、functools.partialを使用して同じタイプの結果を取得することもできます)

別の方法は、ボタンごとに個別のコールバックを作成することです。これにより、コードが重複する可能性があります。


1
これがまさにラムダが何であるかを調べた理由ですが、なぜこれが機能するのか、私には関数を直接呼び出すのとまったく同じに見えます(stackoverflow.com/questions/3704568/…)。遅いかもしれませんが、うまくいきますが、なぜうまくいくのでしょうか?
Rqomey 2013

5
@Rqomey:違いは、この例でvalueはループで定義されていることです。他の例では、パラメーターには常に1つの値しかありませんでした。のようなものを追加するとarg=value、現在の値がコールバックにアタッチされます。それがない場合、コールバックで変数への参照をバインドします。ループの実行がすでに完了してからしばらくするとコールバックが発生するため、参照には常に変数の最終値が含まれます。
ブライアンオークリー

1
私は昨日これを機能させました、正直に言ってそれがどれほど便利であるか信じられません... forループから1つのメニューと構成用のcsvファイルを作成できます。本当に便利なもの。
Rqomey 2013

1
存在に注意してくださいfunctools.partial()あなたはあまり嫌なもの(となしでこれを行うことを可能にするlambda)を。
Gareth Latty 2014年

2
partial(my_callback, value)lambda arg=value: my_callback(arg)-ラムダは、(その後、割り当て引数にと使用)はるかに嫌なものを持っており、それが意図が何であるかあまり明確だ(あなたはラムダで微妙に異なる何かをすることができます)。インポートは実際には問題ありません(とにかく山があり、ファイルごとに1回です)。コードはそれがどれだけうまく読めるかで最もよく判断されpartial()、ラムダよりもはるかに読みやすいです。
Gareth Latty 2014年

58

ラムダがなくなるとは思いません。最終的にそれを削除しようとすることをあきらめることについてのグイドの投稿を見てください。紛争の概要もご覧ください。

Pythonの機能的機能の背後にある取り決めについての詳細は、この投稿をチェックしてください。http//python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html

奇妙なことに、もともとラムダやその他の機能的機能の導入の動機となったmap、filter、reduce関数は、大部分はリスト内包表記とジェネレータ式に取って代わられました。実際、reduce関数はPython 3.0の組み込み関数のリストから削除されました。(ただし、ラムダ、マップ、またはフィルターの削除に関する苦情を送る必要はありません。それらは残っています。:-)

私自身の2セント:明快さに関しては、ラムダがめったに価値がない。一般的に、ラムダを含まないより明確な解決策があります。


2
ただし、reduceはPython 3.0でもインポート可能です。あなたが本当にそれを望めば、あなたはまだそれを持つことができます。
パヴェルPolewicz

グイドの試みは構文に関するものだったと思います。:この人もいることを考えてcackhanded.com/blog/post/2008/01/24/...
leewz

38

Pythonでは、lambda関数をインラインで定義する方法にすぎませんが、

a = lambda x: x + 1
print a(1)

そして..

def a(x): return x + 1
print a(1)

.. まったく同じです。

通常の関数では実行できないようなラムダで実行できることは何もありません。Pythonでは、関数は他のものと同じようにオブジェクトであり、ラムダは単に関数を定義します。

>>> a = lambda x: x + 1
>>> type(a)
<type 'function'>

私は正直に言って、このlambdaキーワードはPythonでは冗長だと思います—私はそれらを使用する必要がありませんでした(または、通常の関数、リスト内包表記、または多くの組み込み関数の1つが代わりによりよく使用される可能性がある場所で使用されたものを見ました)

完全にランダムな例については、記事「Pythonのラムダが壊れている!」

ラムダが壊れているかを確認するには、関数のリストを生成してみてくださいfs=[f0,...,f9]どこにfi(n)=i+n。最初の試み:

>>> fs = [(lambda n: i + n) for i in range(10)]
>>> fs[3](4)
13

私は、たとえそれがうまくいったとしても、それは恐ろしく「unpythonic」であり、同じ機能が他の無数の方法で記述される可能性があると主張します。たとえば、

>>> n = 4
>>> [i + n for i in range(10)]
[4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

はい、同じではありませんが、ラムダ関数のグループをリストで生成する必要がある原因を私は見たことがありません。他の言語では理にかなっているかもしれませんが、PythonはHaskell(またはLisp、または...)ではありません

ラムダを使用しても、この方法で望ましい結果が得られることに注意してください。

>>> fs = [(lambda n,i=i: i + n) for i in range(10)]
>>> fs[3](4)
7

編集:

ラムダが役立ついくつかのケースがあります。たとえば、次のように、PyQtアプリケーションで信号を接続する場合に便利です。

w = PyQt4.QtGui.QLineEdit()
w.textChanged.connect(lambda event: dothing())

ただ実行w.textChanged.connect(dothing)するdothingと、追加のevent引数を指定してメソッドが呼び出され、エラーが発生します。ラムダを使用すると、ラッピング関数を定義しなくても、引数をきちんと削除できます。


2
Python変数のスコープ規則がそのように機能するため、「ラムダが壊れている」引数は壊れています。forループ内でクロージャーを作成した場合も、同じ方法で噛まれます。
Antti Haapala 2013

1
ラムダは、他の多くの言語(javascriptなど)と同様に、ユーザーに「匿名」関数を提供するためのpythonの方法にすぎません。
Stefan Gruenwald 2014年

1
a定義したラムダと関数は完全に同じではありません。:)それら__name__は少なくともフィールドによって異なります...
nperson325681 '06 / 11/14

1
それは単なるインライン関数以上の働きをします。
kta 2015年

「別の言語で意味をなすかもしれない」というあなたの主張は奇妙です。ラムダには本質的な性質があるか、そうでないかのどちらかです。
Titou

31

ラムダは同じことをする関数のリストに役立ちますが、状況は異なります。

同様に、Mozillaの複数のルール

plural_rules = [
    lambda n: 'all',
    lambda n: 'singular' if n == 1 else 'plural',
    lambda n: 'singular' if 0 <= n <= 1 else 'plural',
    ...
]
# Call plural rule #1 with argument 4 to find out which sentence form to use.
plural_rule[1](4) # returns 'plural'

すべての関数を定義する必要がある場合は、関数の終わりまでに気が狂います。
また、それはのような関数名を持つ素敵ではないでしょうplural_rule_1plural_rule_2など、そして、あなたがする必要があると思いeval()ますが、可変機能IDに依存しているときに。


1
これは、F#でこれまでパターンマッチングとオプションを使用して行った短い遭遇に似ています。この構文の使用方法に関する詳細情報はありますか?
Ken

26

あなたが行うことができますほとんど何でもlambdaあなたが名前の関数やリストとジェネレータ式のいずれかでよりよく行うことができます。

したがって、ほとんどの場合、基本的にはどのような状況でも、そのうちの1つだけを使用する必要があります(おそらく、インタラクティブインタープリターで記述されたスクラッチコードを除く)。


3
「ほとんどの場合、基本的にどのような状況でも、そのうちの1つだけを使用してください」期間。インタプリタでラムダを入力しても、それほど役に立ちません。
S.Lott、2009年

11
@ハビエル「ラムダ」のコンセプトについて話しているのなら、私も同感です。ただし、「lambda」についてpythonキーワードを使用している場合は、次のようになります。1)名前付き関数の方が高速で、ラムダ(マップ+フィルター)を使用するほぼすべての場所で(ステートメント+式)より多くのことを実行できます。より高性能で簡潔です。ファーストクラスの関数がクールではないと言っているわけではありません。Pythonの "lambda"キーワードは、名前付き関数を使用するだけでは不十分です。それだけです。
アーロンメンパー09年

3
ラムダは、sort()やsorted()のkey =引数のようなコールバック引数を取る関数で使用するために私にとって不可欠でした
Rick Copeland

19
@リック私は疑いはありませんが、「lambda」が表示され、「zohmygod lambda」と考えてPythonでスキームコードを書き始めた場合、Pythonのラムダ式の制限にがっかりするでしょう。一方、「リスト内包は機能しますか?いいえ。名前付き関数であることのメリットは何ですか?いいえ、わかりました。sorted(xs、key = lambda x:x.name、 x.height) "、ラムダを正しい回数使用することになります。
アーロンメンパー09年

4
+1:ラムダを使用する場合、名前のない関数を使用する場合は、十分に強調できません。そして、名前には貴重な知的付加価値があります。
Stephane Rolland

19

私はPythonを数年使用しており、ラムダが必要なケースに遭遇したことはありません。実際、チュートリアルで述べられているように、これは構文上の砂糖のためだけのものです。


8
彼らは非常にパイソンを使用してGUIを開発するときに便利。多くの場合、ウィジェットは関数への参照を必要とします。関数を呼び出して引数を渡すウィジェットが必要な場合は、lambdaが非常に便利です。
ブライアンオークリー

1
関数に複数の引数を渡すことの利点は何ですか?func_name(a、b):ラムダを使用せずにa + bを返す
16

2
それがいない必要が、それはESP、多くの場合、短いコードと読みやすくを書くことができます。JavaやC ++などの冗長な言語
phuclv 2017

17

Pythonのラムダの特定の実装について話すことはできませんが、一般的にラムダ関数は本当に便利です。これらは関数型プログラミングのコアテクニック(多分THEテクニック)であり、オブジェクト指向プログラムでも非常に役立ちます。特定の種類の問題については、それらが最良の解決策であるため、忘れないでください。

クロージャーマップ関数(python docsにリンクしていますが、関数構造をサポートするほぼすべての言語に存在します)を読んで、なぜそれが役立つのかを確認することをお勧めします。


3
そのことはラムダなしで行うことができます。それは大きな手間です。
ブライアン

17

ラムダ関数は、関数を作成する非官僚的な方法です。

それでおしまい。たとえば、メイン関数があり、値を二乗する必要があるとします。これを行う従来の方法とラムダの方法を見てみましょう。

従来の方法:

def main():
...
...
y = square(some_number)
...
return something

def square(x):
    return x**2

ラムダの方法:

def main():
...
square = lambda x: x**2
y = square(some_number)
return something

違いを見ます?

ラムダ関数は、リスト内包表記やマップなどのリストと非常によく合います。実際、リスト内包表記は、ラムダを使用して自分を表現する「パイソン的な」方法です。例:

>>>a = [1,2,3,4]
>>>[x**2 for x in a]
[1,4,9,16]

構文の各要素の意味を見てみましょう。

[]:「リストをください」

x ** 2:「この新しい関数を使用して」

xのa:「aの各要素へ」

それは便利ですね。このような関数を作成します。ラムダを使って書き換えましょう:

>>> square = lambda x: x**2
>>> [square(s) for x in a]
[1,4,9,16]

次に、同じものですが、より言語に依存しないマップを使用します。Mapsは2つの引数を取ります。

(i)1つの機能

(ii)反復可能

また、各要素がiterableの各要素に適用される関数であるリストを提供します。

したがって、マップを使用すると、次のようになります。

>>> a = [1,2,3,4]
>>> squared_list = map(lambda x: x**2, a)

ラムダとマッピングをマスターすれば、データを簡潔な方法で操作する大きな力が得られます。ラムダ関数は、あいまいではなく、コードの明確さも奪いません。難しいものと新しいものを混同しないでください。それらを使い始めると、非常に明確になります。


13

lambda私の意見では控えめに言ってもいいことの1つは、値が必要になるまで単純なフォームの評価を延期する方法であることです。説明させてください。

多くのライブラリルーチンが実装されているため、特定のパラメーターを呼び出し可能にすることができます(そのうちの1つはラムダです)。実際の値は、それが使用されるとき(呼び出されるときではなく)にのみ計算されるという考え方です。(不自然な)例は、ポイントを説明するのに役立ちます。あなたが与えられたタイムスタンプを記録しようとしていたルーチンがあるとしましょう。ルーチンで現在時刻から30分を引いた時間を使用したいとします。あなたはそのようにそれを呼ぶでしょう

log_timestamp(datetime.datetime.now() - datetime.timedelta(minutes = 30))

次に、特定のイベントが発生したときにのみ実際の関数が呼び出され、その時点でのみタイムスタンプが計算されるようにするとします。あなたはそうすることができます

log_timestamp(lambda : datetime.datetime.now() - datetime.timedelta(minutes = 30))

log_timestampこのような呼び出し可能オブジェクトを処理できると仮定すると、必要なときにこれを評価し、その時点のタイムスタンプを取得します。

もちろん、これを行うには別の方法があります(operatorたとえば、モジュールを使用します)が、私は要点を伝えたと思います。

アップデートここでは、もう少し具体的な現実世界の例があります。

更新2:これはいわゆるサンクの例だと思います。


11

上記のように、Pythonのラムダ演算子は無名関数を定義し、Python関数はクロージャーです。クロージャの概念を演算子のラムダと混同しないようにすることが重要です。演算子のラムダは、それらの構文のメタドンにすぎません。

数年前にPythonを使い始めたとき、リストの理解力とともに、ラムダをかっこいいと思ってよく使用しました。しかし、私はPythonで書かれた大きなWebサイトを作成し、それを維持する必要があります。関数ポイントは数千程度です。私は経験からラムダはプロトタイプを作成しても問題ないかもしれませんが、いくつかのキーストロークを保存することを除いて、インライン関数(名前付きクロージャー)には何も提供しないか、またはそうでない場合があります。

基本的にこれはいくつかのポイントに要約されます:

  • 意味のある名前を使用して明示的に記述されたソフトウェアを読む方が簡単です。名前のない匿名クロージャには、意味のある名前を付けることはできません。この簡潔さは、何らかの理由でラムダパラメータにも感染するように思われるため、ラムダx:x + 1のような例がよく見られます
  • 名前付きクロージャーは、参照する名前がある場合、名前で複数回参照できるため、再利用する方が簡単です。
  • 名前はトレースバックやエラーの前後に表示されるため、ラムダの代わりに名前付きクロージャーを使用しているコードをデバッグする方が簡単です。

それらを切り上げて名前付きクロージャーに変換するのに十分な理由です。しかし、私は匿名の閉鎖に対して2つの恨みを抱いています。

最初の恨みは、それらが言語を散らかす別の不要なキーワードにすぎないということです。

2番目の恨みはより深く、パラダイムレベルにあります。つまり、ラムダ計算はチューリングではないため、メッセージパッシング、オブジェクト指向、または手続き型のスタイルよりも柔軟性が低いため、関数型プログラミングスタイルを促進することは好きではありません。完全(幸運なことにPythonでは、ラムダの内部でも制限から抜け出すことができます)。ラムダがこのスタイルを推進していると私が思う理由は次のとおりです。

  • 暗黙の戻りがあります。つまり、関数である必要があるようです。

  • それらは、別の、より明示的で、より読みやすく、より再利用可能で、より一般的なメカニズムに対する代替の状態隠蔽メカニズムであるメソッドです。

私はラムダフリーのPythonを一生懸命書き、ラムダを削除しました。Pythonはラムダなしでは少し優れた言語になると思いますが、それは私の意見です。


1
「... Pythonの関数はクロージャです」。私が理解しているように、それは正しくありません。クロージャは関数ですが、関数は必ずしもクロージャではありません。関数->ラムダx、y:x + y。Closure-> lambda x:lambda y:x + y
0atman

6
「ラムダ計算はチューリング完全ではないので」というのは明らかに間違っており、型付けされていないラムダ計算ISチューリング完了です。あなたは、Yコンビネータを使って再帰、取得することができますY = lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args)))
アンティHaapala

さらに、チューリングの完全性についてウィキペディアにアクセスすると、「古典的な例はラムダ計算です」と書かれています。
Antti Haapala 2013

真剣に-完全なチューリングではありません-この回答には真剣な編集または撤回が必要です。
トニーサフォーク66

@MarcinŁośKISSに準拠しているため、賛成票が入りました。比較として、K&Rブックでは、代入を部分として使用するか、より大きな式を使用するとよりコンパクトになりますが、多くの場合、読みにくくなります。関数型プログラミングパターンを使用するトレンドワゴンは、陳腐で陳腐なものです。それらがどのように使用されるかを述べることで十分ですが、有能な開発者になることを最優先することを述べることは熱狂的です。完全に主観的。この議論は、クラスのない言語は原始的で劣っており不十分であると主張するC ++開発者に似ています。「チューリング完全性」、議論は教訓的です。
typedeaf 2017

11

ラムダは実際には関数型プログラミングのアイデアから生まれた非常に強力な構造体であり、Pythonの近い将来に決して簡単に変更、再定義、または削除されるものではありません。これらは、関数をパラメーターとして渡すことができるため、より強力なコードを作成するのに役立ちます。したがって、一流の市民としての関数のアイデアです。

ラムダは混乱する傾向がありますが、しっかりとした理解が得られたら、次のようなクリーンでエレガントなコードを書くことができます。

squared = map(lambda x: x*x, [1, 2, 3, 4, 5])

上記のコード行は、リスト内の数値の二乗のリストを返します。もちろん、次のようにすることもできます。

def square(x):
    return x*x

squared = map(square, [1, 2, 3, 4, 5])

前者のコードの方が短いことは明らかです。これは、map関数(または関数をパラメーターとして受け取る同様の関数)を1か所だけで使用する場合に特に当てはまります。これにより、コードがより直感的でエレガントになります。

また、@ David Zaslavskyが彼の回答で述べたように、リストが何らかの不明瞭な数学的な方法から値を取得する必要がある場合は、リスト内包表記が常にうまくいくとは限りません。

より実用的な観点から見ると、最近のラムダの最大の利点の1つは、GUIとイベント駆動型プログラミングにあります。Tkinterのコールバックを見ると、それらが引数として取るのは、それらをトリガーしたイベントだけです。例えば

def define_bindings(widget):
    widget.bind("<Button-1>", do-something-cool)

def do-something-cool(event):
    #Your code to execute on the event trigger

次に、渡す引数がある場合はどうでしょうか。マウスクリックの座標を格納するために2つの引数を渡すだけの簡単なもの。次のように簡単に行うことができます。

def main():
    # define widgets and other imp stuff
    x, y = None, None
    widget.bind("<Button-1>", lambda event: do-something-cool(x, y))

def do-something-cool(event, x, y):
    x = event.x
    y = event.y
    #Do other cool stuff

これはグローバル変数を使用して実行できると主張できますが、特にグローバル変数が特定の場所でのみ使用される場合は、メモリ管理とリークを心配して頭を痛めたくありませんか?それは単に貧弱なプログラミングスタイルになるでしょう。

要するに、ラムダは素晴らしく、決して過小評価すべきではありません。PythonのラムダはLISPのラムダ(より強力です)とは異なりますが、実際にはたくさんの魔法のラムダを使用できます。


ありがとう。私はあなたの最後の例を完全に理解していませんでした。どのようにX来るとyは両方で定義されているmaindo_something_cool?何が起こるにxし、y機能に?渡された値はすぐに上書きされるようですか?関数はどのように知っていeventますか?コメント/説明を追加してもらえますか?ありがとう
Sanjay Manohar 2015

私は渡してい@SanjayManohar xyの引数としてdo-something-cool、その値は、あなたは何も期待されていない引数を渡すためにラムダを使用する方法を説明するために機能で設定されています。widget.bind機能は期待eventその特定のウィジェットをGUIイベントを特定するパラメータ。より明確にするために、Tkinterのプログラミングモデルを読むことをお勧めします。
varagrawal 2015

うーん、Tkinterモデルを理解していると思います。しかし、それでもまだよくわかりx,yませんx=event.x。それはあなたが渡した値を上書きしませんか?そして、関数はどのようにしてそれが何でeventあるかを知っていますか?それを関数に渡す場所がわかりません。それともメソッドですか?また、関数名にマイナス記号を使用できますか?
Sanjay Manohar、2015

@SanjayManoharの相棒、TkinterとPythonを読む必要があります。Tkinterは、イベントオブジェクトに関数をデフォルトアクションとして渡します。についてはx, y、これは説明のための単なる例です。私はTkinterではなくラムダの力を見せようとしています。:)
varagrawal 2015

1
eventさて、私はあなたが意図したものを見ました-あなたは関数が受け取りたいですか?その場合、あなたのラムダは読んではいけませんlambda event: do_something_cool(event,x,y)か?
Sanjay Manohar、2015

8

ラムダは、一般に関数型プログラミングスタイルと深く関連しています。関数にデータを適用して結果をマージすることで問題を解決できるという考えは、Googleがアルゴリズムのほとんどを実装するために使用するものです。

関数型プログラミングスタイルで記述されたプログラムは簡単に並列化できるため、最新のマルチコアマシンではますます重要になっています。要するに、いや、あなたはそれらを忘れてはいけません。


7

最初にラムダを理解できたおめでとうございます。私の意見では、これは行動するための本当に強力な構成要素です。最近の関数型プログラミング言語への傾向は、それを避けてはならず、近い将来に再定義されることもないことを示しています。

あなたは少し違う考えをする必要があります。きっと気に入ると思います。ただし、Pythonのみを扱う場合は注意してください。ラムダは実際のクロージャーではないため、どういうわけか「壊れています」:pythonラムダが壊れています


Pythonのラムダは壊れていません。ラムダでローカルを処理する方法は2つあります。どちらにも長所と短所があります。Python(およびC#)が採用したアプローチは、純粋に関数型言語に慣れている人にはおそらく直感に反するものだと思います。
ブライアン

それは確かに直感に反しています。私はpythonプログラマではありませんが、きしむスモールトークでは同じであり、定期的にこれに取り組みます。だから私はそれを「壊れた」と考えます:)
Norbert Hartl

いいえ、これは反直感とは関係ありません。変数名の字句スコープが関数のスコープであることだけです。ループは字句スコープを導入しません。関数もJavaScriptで同じように機能します。varのスコープが必要な場合は、いつでも行うことができます(lambda scopedvar:lambda x:scopedvar + x)()
Antti Haapala

6

私はPythonを始めたばかりで、最初にLambdaに向かいました-理解するのにしばらく時間がかかりました。

これは何かを非難するものではないことに注意してください。誰もが簡単に来ないさまざまなものを持っています。

ラムダは、実生活で忘れられるべき「興味深い」言語アイテムの1つですか?

番号。

それが必要になるかもしれないいくつかのエッジケースがあると私は確信していますが、それが曖昧であることを考えると、

あいまいではありません。私が取り組んできた過去2つのチームでは、誰もがこの機能を常に使用していました。

将来のリリースで再定義される可能性(さまざまな定義に基づく私の仮定)

数年前にクロージャのセマンティクスを修正する以外に、Pythonで再定義するという深刻な提案はありません。

コーディングの明確性の低下-回避すべきですか?

正しく使用していれば、それほど明確ではありません。逆に、より多くの言語構成を利用できるようにすると、明確さが増します。

これは、C型のオーバーフロー(バッファオーバーフロー)を思い出します-最上位の変数をポイントし、他のフィールド値を設定するためにオーバーロードしています...技術者のショーマンシップの一種ですが、メンテナンスコーダーの悪夢...

ラムダはバッファオーバーフローのようなものですか?ワオ。「メンテナンスの悪夢」だと思えば、ラムダをどのように使用しているのか想像できません。


5
私(および他の人)に質問全体をもう一度読ませるには-1。他の人がそれをせずに答えることができたことに注意してください。
パヴェルPolewicz

6

コードの重複を避けるためにラムダを使用しています。それは機能を簡単に理解できるようにするでしょう。

def a_func()
  ...
  if some_conditon:
     ...
     call_some_big_func(arg1, arg2, arg3, arg4...)
  else
     ...
     call_some_big_func(arg1, arg2, arg3, arg4...)

私はそれを一時ラムダで置き換えます

def a_func()
  ...
  call_big_f = lambda args_that_change: call_some_big_func(arg1, arg2, arg3, args_that_change)
  if some_conditon:
     ...
     call_big_f(argX)
  else
     ...
     call_big_f(argY)

5

今日、David Mertzの本「Pythonでのテキスト処理」を読み始めました。彼はラムダのかなり簡潔な説明を持っていますが、最初の章の例と付録Aの説明を組み合わせると、ページから飛び出し(最終的に)、突然、私はそれらの価値を理解しました。それは彼の説明があなたにとってうまくいくと言っているわけではなく、私はまだ発見の段階にあるので、次のこと以外はこれらの応答に追加しようとはしません:私はPythonが初めてです。今私はメルツを読んだので、私はそれらを理解し、プログラミングへのよりクリーンなアプローチを可能にするので、それらは非常に有用であると思います。

彼は、Zen of Pythonを再現しています。その1行は、SimpleがComplexより優れています。OOPを使用しないプログラマーがラムダを使ってコードを読んでいるとき(そして先週まで、リストの理解度を理解していました)、これは簡単だと思いました。。実際にこれらの機能がコードを読みやすくし、代替手段よりも理解しやすくなることに、ついに私はようやく気づきました。これは常にある種のループです。財務諸表のように、Pythonは初心者ユーザー向けではなく、教育を受けたいユーザー向けに設計されていることにも気付きました。私はこの言語がどれほど強力であるか信じられません。(ついに)ラムダの目的と価値が明らかになったとき、約30のプログラムをまとめて、適切な場所にラムダを最初から入れたかった。


5

ラムダを使用する場合に役立つのは、長いリスト内包の読みやすさ向上させることです。この例でloop_dicは、わかりやすくするために短くしていますがloop_dic、非常に長いと想像してください。iその値のラムダバージョンの代わりにインクルードするプレーンな値を使用する場合は、を取得しNameErrorます。

>>> lis = [{"name": "Peter"}, {"name": "Josef"}]

>>> loop_dic = lambda i: {"name": i["name"] + " Wallace" }
>>> new_lis = [loop_dic(i) for i in lis]

>>> new_lis
[{'name': 'Peter Wallace'}, {'name': 'Josef Wallace'}]

の代わりに

>>> lis = [{"name": "Peter"}, {"name": "Josef"}]

>>> new_lis = [{"name": i["name"] + " Wallace"} for i in lis]

>>> new_lis
[{'name': 'Peter Wallace'}, {'name': 'Josef Wallace'}]

5

私が実際に深刻なラムダを必要とした例を挙げましょう。私はグラフィカルプログラムを作成しています。このプログラムでは、ファイルを右クリックして、3つのオプションのいずれかに割り当てます。Tkinter(これを書いているGUIインターフェイスプログラム)では、誰かがボタンを押すと、引数を受け取るコマンドに割り当てることができないことがわかりました。したがって、いずれかのオプションを選択し、選択した結果を次のようにしたい場合:

print 'hi there'

その後、大したことはありません。しかし、特定の詳細を選択する必要がある場合はどうでしょうか。たとえば、選択肢Aを選択すると、選択肢A、B、またはCに依存する引数を取る関数を呼び出しますが、TKinterはこれをサポートできませんでした。ラムダはこれを実際に回避する唯一のオプションでした...


2
まあ、たぶんあなたはそうするのではなくdef foo...、それを渡したのでしょう。それはただのコードであり、名前を付けなければなりません。foolambda
Jon Coombs、2014

4

主にnullオブジェクトとして、またはパラメーターを関数に部分的にバインドするために、私はそれをかなり頻繁に使用します。

次に例を示します。

nullオブジェクトパターンを実装するには:

{
    DATA_PACKET: self.handle_data_packets
    NET_PACKET: self.handle_hardware_packets
}.get(packet_type, lambda x : None)(payload)

パラメータバインディングの場合:

私は次のAPIを持っているとしましょう

def dump_hex(file, var)
    # some code
    pass

class X(object):
    #...
    def packet_received(data):
        # some kind of preprocessing
        self.callback(data)
    #...

次に、受信したデータをファイルにすばやくダンプしたくない場合は、次のようにします。

dump_file = file('hex_dump.txt','w')
X.callback = lambda (x): dump_hex(dump_file, x)
...
dump_file.close()

4

lambdaパラメータを含むコールバックを作成するために使用します。同じ機能を実行するメソッドを記述するよりも、1行でラムダを記述する方がわかりやすくなります。

例えば:

import imported.module

def func():
    return lambda: imported.module.method("foo", "bar")

とは対照的に:

import imported.module

def func():
    def cb():
        return imported.module.method("foo", "bar")
    return cb

4

私はPythonの初心者なので、ラムダの明確なアイデアを取得するために、「for」ループと比較しました。効率の面で。これがコードです(python 2.7)-

import time
start = time.time() # Measure the time taken for execution

def first():
    squares = map(lambda x: x**2, range(10))
    # ^ Lambda
    end = time.time()
    elapsed = end - start
    print elapsed + ' seconds'
    return elapsed # gives 0.0 seconds

def second():
    lst = []
    for i in range(10):
        lst.append(i**2)
    # ^ a 'for' loop
    end = time.time()
    elapsed = end - start
    print elapsed + ' seconds'
    return elapsed # gives 0.0019998550415 seconds.

print abs(second() - first()) # Gives 0.0019998550415 seconds!(duh)

6
このtimeitモジュールは、通常、time.time()値を減算するよりも正確な結果をもたらします。
ケビン

2
うーん、first()とsecond()の開始時にタイマーを再起動する必要はありませんか?
qneill

2

ラムダは手続きコンストラクタです。Pythonのラムダはそれほど強力ではありませんが、実行時にプログラムを合成できます。この種のプログラミングを理解している人はほとんどいないことに注意してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.