Pythonのラムダを見つけようとしています。ラムダは、実際には忘れられるべき「興味深い」言語項目の1つですか。
それが必要とされるかもしれないいくつかのEdgeのケースがあると確信しています、それのあいまいさ、将来のリリースで再定義される可能性(それのさまざまな定義に基づく私の仮定)避けるべきですか?
これはC型のオーバーフロー(バッファオーバーフロー)を思い出させます - 一番上の変数を指し、他のフィールド値を設定するためにオーバーロードします。それは一種の技術的なショーマンシップだがメンテナンスコーダーの悪夢のように感じる。
ラムダ関数について話していますか ?好き
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]
私はラムダ関数を定期的に使っています。慣れるまで少し時間がかかりましたが、結局私はそれらが言語の非常に価値のある部分であることを理解するようになりました。
lambda
は、単にfunction
と言う空想的な方法です。その名前以外には、それについてあいまい、威圧的、または不可解なことは何もありません。次の行を読むときは、lambda
をfunction
に置き換えてください。
>>> f = lambda x: x + 1
>>> f(3)
4
それはx
の関数を定義するだけです。 R
のような他のいくつかの言語は、それを明示的に言っています:
> f = function(x) { x + 1 }
> f(3)
4
分かりますか?それはプログラミングでするべき最も自然なことの1つです。
2行の要約:
lambda
キーワード:不要、時には便利。リモートで複雑なことをしている場合は、それを片付けて実際の機能を定義してください。ラムダは高階関数を扱う非常に重要な抽象化メカニズムの一部です。その価値を正しく理解するために、 AbelsonとSussman から高品質のレッスンを見て、本を読んでください _ sicp _
これらは現代のソフトウェアビジネスに関連する問題であり、ますます人気が高まっています。
私はラムダが消えるのではないかと思います。最後にそれを削除しようとするのをやめることについては Guido's post を見てください。 競合の概要 も参照してください。
あなたはPythonの機能的な機能の背後にある取り引きについてのより多くの歴史についてのこの記事をチェックするかもしれません: http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html
奇妙なことに、もともとラムダおよび他の機能的特徴の導入を動機づけたmap、filter、およびreduce関数は、大部分はリスト内包表記および生成式によって置き換えられました。事実、reduce関数はPython 3.0の組み込み関数のリストから削除されました。 (ただし、ラムダ、マップ、またはフィルタの削除に関する苦情を送信する必要はありません。それらは残っています。:-)
私自身の2セント:明快さが及ぶ限りでは、それだけの価値があるラムダです。一般的にはラムダを含まないもっと明確な解決策があります。
ラムダは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 を使用しても同じ結果を得ることができます)
別の方法としては、ボタンごとに別々のコールバックを作成することで、コードが重複する可能性があります。
Pythonでは、lambda
は関数をインラインで定義するための単なる方法です。
a = lambda x: x + 1
print a(1)
そして..
def a(x): return x + 1
print a(1)
.. {exactと同じです。
通常の関数ではできない、lambdaでできることは何もありません。Pythonでは、関数は他のものとまったく同じオブジェクトであり、lambdaは単に関数を定義するだけです。
>>> a = lambda x: x + 1
>>> type(a)
<type 'function'>
私はlambda
キーワードがPythonで冗長であると正直に思っています - 私はそれらを使う必要性を全く持っていませんでした(あるいは通常の関数、リスト内包、あるいは多くの組み込み関数の代わりに使われるかもしれないところで使われるのを見ません)
完全にランダムな例については、記事「 Pythonのラムダが壊れています」から。 :
ラムダがどのように壊れているかを見るには、関数のリスト
fs=[f0,...,f9]
を生成してみてください。ここでfi(n)=i+n
。最初の試み:>>> fs = [(lambda n: i + n) for i in range(10)] >>> fs[3](4) 13
たとえそれがうまくいったとしても、それは恐ろしくて「愚痴」であり、同じ機能が他にも無数の方法で書かれる可能性があります。
>>> n = 4
>>> [i + n for i in range(10)]
[4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
はい、それは同じではありませんが、リストにラムダ関数のグループを生成することが要求される原因となった never があります。他の言語でも意味があるかもしれませんが、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
メソッドが呼び出され、エラーが発生します。ラムダを使用することは、折り返し関数を定義する必要なしに引数をきちんと落とすことができることを意味します。
ラムダは同じことをするが異なる状況のための関数のリストに役立つと思います。 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_1
、plural_rule_2
などのような関数名ではそれはいいことではありません。そして変数function idに頼っているときはeval()
する必要があります。
lambda
を使ってできることのほとんどすべては、名前付き関数またはリスト式とジェネレータ式のいずれかを使ってよりよくできます。
したがって、ほとんどの場合、基本的にはあらゆる状況でそれらのうちの1つだけを使用する必要があります(おそらく対話式インタプリタで書かれたスクラッチコードを除く)。
私は数年前からPythonを使ってきましたが、 needed lambdaを使ったことがありませんでした。本当に、 tutorial が述べているように、それは単なるシンタックスシュガー用です。
Lambda関数これは関数を作成するための非官僚的な方法です。
それでおしまい。例えば、あなたがあなたの主な機能を持ち、値を二乗する必要があるとしましょう。これを行うための伝統的な方法とラムダの方法を見てみましょう。
伝統的な方法:
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
違いを見ます?
Lambda関数は、リスト内包表記やマップのように、リストに非常に適しています。実際、リスト内包表記はラムダを使って自分自身を表現するための「Pythonic」方法です。例:
>>>a = [1,2,3,4]
>>>[x**2 for x in a]
[1,4,9,16]
構文の各要素の意味を見てみましょう。
[]:「リストをください」
x ** 2: "この生まれたばかりの関数を使う"
a内のxについて "内の各要素へ"
それは便利ですね。このような機能を作成します。 lambdaを使って書き換えましょう。
>>> square = lambda x: x**2
>>> [square(s) for x in a]
[1,4,9,16]
それでは、mapを使用しましょう。これは同じことですが、より言語に中立です。 Mapsは2つの引数を取ります。
(i)一つの機能
(ii)イテラブル
そして各要素がイテラブルの各要素に適用される関数であるリストをあなたに与えます。
だから、mapを使うと次のようになります。
>>> a = [1,2,3,4]
>>> squared_list = map(lambda x: x**2, a)
あなたがラムダとマッピングを習得すれば、あなたはデータを簡潔な方法で操作する大きな力を持つでしょう。ラムダ関数はあいまいでもなく、コードの明快さも奪いません。難しいことを新しいことと混同しないでください。それらを使い始めると、それは非常に明確にわかります。
私の考えでは、lambda
のいいところの1つは控えめに言っても、値が必要になるまで単純なフォームの評価を延期する方法です。説明させてください。
多くのライブラリルーチンは、特定のパラメータを呼び出し可能にすることができるように実装されています(そのうちの1つはlambdaです)。その考えは、実際の値はそれが使われる時にだけ計算されるということです(それが呼ばれる時ではなく)。 (考案された)例がその点を説明するのに役立つかもしれません。与えられたタイムスタンプをログに記録しようとしていたルーチンがあるとします。現在の時間から30分を引いたものをルーチンに使用させたいとします。あなたはそれを好きだと思います
log_timestamp(datetime.datetime.now() - datetime.timedelta(minutes = 30))
ここで、実際の関数が特定のイベントが発生したときにのみ呼び出され、その時点でのみタイムスタンプを計算したいとします。あなたはこんなことができます
log_timestamp(lambda : datetime.datetime.now() - datetime.timedelta(minutes = 30))
log_timestamp
がこのようにcallableを扱うことができると仮定すると、それは必要なときにこれを評価し、その時にタイムスタンプを取得します。
これを行うにはもちろん他の方法(例えばoperator
モジュールを使用)もありますが、その点を説明していただければと思います。
更新 : Here は、もう少し具体的な実例です。
Update 2 :これはいわゆる さんく の一例だと思います。
上記のように、Pythonのラムダ演算子は無名関数を定義し、Pythonでは関数はクロージャです。クロージャーの概念と、ラムダ演算子を混同しないようにすることが重要です。演算子ラムダは、単なる構文上のメタドンです。
数年前に私がPythonで始めたとき、私はラムダをよく使っていました。しかし、私は数千の機能点のオーダーで、Pythonで書かれた大きなWebサイトを書いて維持しなければなりません。経験から、ラムダはプロトタイプを作成するのにはいいかもしれませんが、キーストロークをいくつか保存することを除いて、インライン関数(クロージャと呼ばれる)には何も提供しないことを学びました。
基本的にこれはいくつかの点に要約されます。
それらを切り上げて名前付きクロージャに変換するのに十分な理由です。しかし、私は匿名の閉鎖に対して2つの恨みを抱いています。
最初の恨みは、単にそれらが言語を雑然とさせる別の不要なキーワードであるということです。
第二の恨みはより深くそしてパラダイムレベルにあります。すなわち、ラムダ計算がチューリングではないので、それらが関数型プログラミングスタイルを推進するのは好きではありません。完全なものです(幸運にもPythonでは、ラムダの中でさえその制限から抜け出すことができます)。ラムダがこのスタイルを推進していると感じる理由は以下のとおりです。
暗黙の復帰があります、すなわち、それらは機能であるべきであるように見えます。
それらは、他の、より明確で、より読みやすく、より再利用可能で、そしてより一般的なメカニズムである、メソッドに対する代替の状態隠蔽メカニズムです。
私は、ラムダフリーのPythonを書くことと、目に見えるラムダを取り除くことに一生懸命に努力しています。私はPythonがラムダのない少し良い言語になると思いますが、それは私の意見です。
ラムダは、実際には関数型プログラミングのアイデアに由来する非常に強力な構成要素であり、近い将来の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のラムダと同じではありません(より強力です)が、実際にはたくさんの魔法のことができます。
ラムダは一般的に関数型プログラミングスタイルと深く関連しています。あるデータに関数を適用し、その結果をマージすることで問題を解決できるという考えは、Googleがそのアルゴリズムのほとんどを実装するために使用しているものです。
関数型プログラミングスタイルで書かれたプログラムは簡単に並列化されるため、最近のマルチコアマシンではますます重要になっています。だから、要するに、あなたはそれらを忘れてはいけません。
ラムダを把握できた最初のおめでとうございます。私の意見では、これは一緒に行動するための本当に強力な構成要素です。関数型プログラミング言語への最近の傾向は、それが避けられるべきでもなければ近い将来再定義されるべきでもないことを確実に示しています。
あなたはちょっと違うことを考えなければなりません。きっとあなたはそれを気に入ると確信しています。しかし、あなたがpythonだけを扱う場合は注意してください。ラムダは実際のクロージャではないので、どういうわけか「壊れています」: pythonsラムダは壊れています
コードの重複を避けるためにラムダを使います。それは関数を分かりやすくするでしょう。例:
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)
私は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)
ラムダを使うための便利なケースは 長いリストの内包表記の読みやすさを改善することです 。この例では、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'}]
私はPythonを始めたばかりで、最初にLambdaにぶつかりました。
これは何の非難でもないことに注意してください。誰もが簡単にはやって来ないさまざまなものを持っています。
ラムダは、実際の生活で忘れられるべき「興味深い」言語項目の1つですか?
いや.
必要になる可能性のあるEdgeのケースがいくつかあると確信していますが、その曖昧さを考えると、
あいまいではありません。私が取り組んできた過去2つのチームは、誰もがこの機能を常に使用していました。
将来のリリースで再定義される可能性(さまざまな定義に基づく私の仮定)
数年前にクロージャーのセマンティクスを修正する以外に、Pythonでそれを再定義するという真剣な提案を見たことはありません。
コーディングの明確さの低下-避けるべきですか?
あなたがそれを正しく使用している場合、それはそれほど明確ではありません。それどころか、より多くの言語構成要素を利用可能にする増加明快。
これは、C型のオーバーフロー(バッファオーバーフロー)を思い出させます-一番上の変数を指し、他のフィールド値を設定するためにオーバーロードします。
ラムダはバッファオーバーフローのようなものですか?ワオ。 「メンテナンスの悪夢」だと思うなら、ラムダの使い方を想像することはできません。
私はDavid Mertzの本「Pythonでのテキスト処理」を読み始めました。彼はLambdaのかなり簡潔な説明をしていますが、最初の章の例を付録Aの説明と組み合わせることで、私のためにページから飛び降りるようになりました。それは彼の説明があなたのために働くと言うことではなく、私はまだ発見段階にいるので、私はこれらの応答に以下を除いて追加しようとしないでしょう:私はOOPラムダは私にとって奮闘していました私がメルツを読んだ今、私はそれらを手に入れたと思います、そして私は彼らがプログラミングへのよりきれいなアプローチを許すと思うのと同じくらい非常に役に立つと思います。
彼はPythonのZenを再現しています。 単純は複雑よりも優れています。 OOP以外のプログラマがラムダを使ってコードを読む(そして先週のリスト内包表記まで)これは簡単ですか?。私はついに今日これらの機能が実際にコードをはるかに読みやすく、そして他のものより理解しやすいものにすることに気づきました - それは常にある種のループです。私はまた財務諸表のように - Pythonは初心者ユーザーのために設計されたのではなく、むしろ教育を受けたいユーザーのために設計されたことに気付きました。この言語がどれほど強力であるか私は信じられない。それが私に(ついに)ラムダの目的と価値を見いだしたとき、私は約30のプログラムを切り上げて、適切なところにラムダを入れることからやり直すことを望みました。
私は実際に私が実際にラムダを必要としている例をあなたに与えることができます。私はグラフィカルプログラムを作成しています。そこでは、ユーザーがファイルを右クリックして3つのオプションのうちの1つを割り当てます。 Tkinter(私がこれを書いているGUIインターフェースプログラム)では、誰かがボタンを押すと、それは引数を取るコマンドに割り当てられないことがわかります。それで、私が選択肢の1つを選んで、私の選択の結果がであることを望むならば:
print 'hi there'
大したことはありません。しかし、私が特定の詳細を知るために私の選択が必要ならばどうでしょうか。たとえば、選択肢Aを選択した場合、選択肢A、B、またはCに依存する引数を取り込む関数を呼び出します。TKinterはこれをサポートできませんでした。ラムダは実際にこれを回避する唯一の選択肢でした...
パラメータを含むコールバックを作成するために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
主に 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()
Lambdaはプロシージャコンストラクタです。実行時にプログラムを合成することはできますが、Pythonのラムダはそれほど強力ではありません。そのようなプログラミングを理解している人はほとんどいません。