121

私は主にラムダ関数を使用しますが、同じ動作を提供するように見えるネストされた関数を使用することもあります。

どちらかが別の関数内で見つかった場合、機能的に同じことを行ういくつかの簡単な例を次に示します。

ラムダ関数

>>> a = lambda x : 1 + x
>>> a(5)
6

ネストされた関数

>>> def b(x): return 1 + x

>>> b(5)
6

どちらか一方を使用する利点はありますか? (パフォーマンス? 読みやすさ? 制限? 一貫性? など)

それも問題ですか?そうでない場合は、Pythonic の原則に違反しています。

それを行う明白な方法が 1 つ (できれば 1 つだけ) ある必要があります。.

4

16 に答える 16

126

lambdaを名前に割り当てる必要がある場合は、def代わりに a を使用してください。defs は、代入の構文糖衣にすぎないため、結果は同じであり、はるかに柔軟で読みやすいです。

lambdas は1 回だけ使用でき、名前のない関数は破棄します。

ただし、この使用例は非常にまれです。名前のない関数オブジェクトを渡す必要はほとんどありません。

ビルトインmap()filter()関数オブジェクトが必要ですが、リスト内包表記とジェネレーター式は、一般にこれらの関数よりも読みやすく、ラムダを必要とせずにすべてのユース ケースをカバーできます。

本当に小さな関数オブジェクトが必要な場合は、代わりにoperatorモジュール関数を使用する必要があります。operator.addlambda x, y: x + y

カバーされていないものがまだ必要な場合は、読みやすくするために , をlambda書くことを検討してください。関数がモジュールdefの関数よりも複雑な場合は、おそらく a の方が適しています。operatordef

そのため、実際の良いlambdaユースケースは非常にまれです。

于 2008-09-25T17:16:31.257 に答える
35

実際には、私には 2 つの違いがあります。

1つ目は、彼らが何をして何を返すかについてです:

  • def は、何も返さず、ローカル名前空間に「名前」を作成するキーワードです。

  • lambda は、関数オブジェクトを返し、ローカル名前空間に「名前」を作成しないキーワードです。

したがって、関数オブジェクトを受け取る関数を呼び出す必要がある場合、1 行の Python コードでそれを行う唯一の方法は、ラムダを使用することです。def に相当するものはありません。

一部のフレームワークでは、これは実際には非常に一般的です。たとえば、私はTwistedをよく使っているので、次のようなことをしています。

d.addCallback(lambda result: setattr(self, _someVariable, result))

は非常に一般的で、ラムダを使用するとより簡潔になります。

2 番目の違いは、実際の関数が実行できることに関するものです。

  • 「def」で定義された関数には、任意の Python コードを含めることができます
  • 'lambda' で定義された関数は式に評価される必要があるため、print、import、raise などのステートメントを含めることはできません。

例えば、

def p(x): print x

期待どおりに動作しますが、

lambda x: print x

SyntaxError です。

もちろん、回避策はあります -またはで置き換えprintてください。しかし、通常、その場合は関数を使用する方がよいでしょう。sys.stdout.writeimport__import__

于 2008-09-26T10:20:43.307 に答える
27

このインタビューで、 Guido van Rossum は、「ラムダ」を Python に入れなければよかったと言っています。

" Q. Python で最も満足して

いない機能は?は、小さな無名関数を作成できるキーワードです。map、filter、reduce などの組み込み関数は、リストなどのシーケンス型に対して関数を実行します。

実際には、それほどうまくいきませんでした。Python には、ローカルとグローバルの 2 つのスコープしかありません。ラムダが定義されたスコープ内の変数にアクセスしたいことがよくありますが、2 つのスコープのためにアクセスできないため、ラムダ関数を記述するのは面倒です。これを回避する方法はありますが、それはちょっと面倒です。多くの場合、Python では、ラムダ関数をいじる代わりに for ループを使用する方がはるかに簡単に思えます。map と friends は、必要な機能を実行する組み込み関数が既に存在する場合にのみうまく機能します。

IMHO、Iambdas は便利な場合もありますが、通常は読みやすさを犠牲にして便利です。これが何をするのか教えてください:

str(reduce(lambda x,y:x+y,map(lambda x:x**x,range(1,1001))))[-10:]

私はそれを書きましたが、それを理解するのに1分かかりました。これは Project Euler からのものです。スポイラーが嫌いなので、どの問題かは言いませんが、0.124 秒で実行されます :)

于 2008-09-25T17:29:26.450 に答える
12

n=1000 の場合、関数とラムダを呼び出す時間は次のとおりです。

In [11]: def f(a, b):
             return a * b

In [12]: g = lambda x, y: x * y

In [13]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    f(a, b)
   ....:
100 loops, best of 3: 285 ms per loop

In [14]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    g(a, b)
   ....:
100 loops, best of 3: 298 ms per loop

In [15]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    (lambda x, y: x * y)(a, b)
   ....:
100 loops, best of 3: 462 ms per loop
于 2012-08-16T13:16:40.080 に答える
8

パフォーマンス:

で関数を作成すると、で作成するよりlambdaわずかに高速defです。違いはdef、ローカル テーブルに名前エントリを作成することによるものです。結果の関数の実行速度は同じです。


読みやすさ:

Lambda 関数は、ほとんどの Python ユーザーにとってやや読みにくいですが、状況によってははるかに簡潔です。非機能ルーチンから機能ルーチンへの変換を検討してください。

# Using non-functional version.

heading(math.sqrt(v.x * v.x + v.y * v.y), math.atan(v.y / v.x))

# Using lambda with functional version.

fheading(v, lambda v: math.sqrt(v.x * v.x + v.y * v.y), lambda v: math.atan(v.y / v.x))

# Using def with functional version.

def size(v):
    return math.sqrt(v.x * v.x + v.y * v.y)

def direction(v):
    return math.atan(v.y / v.x)

deal_with_headings(v, size, direction)

ご覧のとおり、機能バージョンに変換するには、元の非機能バージョンにlambda追加するだけでよいという意味で、バージョンは短く、「より簡単」です。lambda v:また、はるかに簡潔です。しかし覚えておいてください、多くの Python ユーザーはラムダ構文に混乱するでしょう。そのため、長さと実際の複雑さで失ったものは、仲間のコーダーからの混乱で取り戻される可能性があります。


制限:

  • lambda関数は、変数名に割り当てられていない限り、一度しか使用できません。
  • lambda変数名に割り当てられた関数は、def関数よりも有利ではありません。
  • lambda関数はピクルするのが困難または不可能な場合があります。
  • def関数の名前は、合理的に説明的で一意であるか、少なくともスコープ内で使用されないように慎重に選択する必要があります。

一貫性:

Python は、関数型プログラミングの規則をほとんど避けて、手続き型でより単純な目的セマンティクスを採用しています。オペレーターは、このlambdaバイアスとは正反対です。さらに、すでに普及している の代替として、def関数lambdaは構文に多様性を追加します。一貫性が低いと考える人もいます。


既存の機能:

他の人が指摘したように、フィールドでの の多くの使用は、または他のモジュールlambdaのメンバーに置き換えることができます。operator例えば:

do_something(x, y, lambda x, y: x + y)
do_something(x, y, operator.add)

多くの場合、既存の関数を使用すると、コードが読みやすくなります。


Pythonic の原則: 「それを行うための明白な方法は 1 つ、できれば 1 つだけであるべきです」</p>

これは、唯一の真実の情報源の原則に似ています。残念なことに、単一の明白な方法を実行するという原則は、真の指針となる原則ではなく、Python にとって常に物欲しそうな願望でした。Python の非常に強力な配列内包表記について考えてみましょう。mapこれらは、 関数と 関数と機能的に同等filterです。

[e for e in some_array if some_condition(e)]
filter(some_array, some_condition)

lambdadef同じです。

それは意見の問題ですが、明らかに何かを壊さない一般的な使用を意図した Python 言語は、十分に「Pythonic」であると言えます。

于 2016-02-11T18:14:36.767 に答える
6

nosklo のアドバイスに同意します。関数に名前を付ける必要がある場合は、def. lambdaコードの短いスニペットを別の関数に渡すだけの場合のために関数を予約します。

a = [ (1,2), (3,4), (5,6) ]
b = map( lambda x: x[0]+x[1], a )
于 2008-09-25T17:19:48.253 に答える
6

他の回答に同意する一方で、読みやすい場合もあります。lambdaこれは、私が N 次元に遭遇し続けるユースケースで便利な例defaultdictです。
次に例を示します。

from collections import defaultdict
d = defaultdict(lambda: defaultdict(list))
d['Foo']['Bar'].append(something)

def2 番目の次元の を作成するよりも読みやすいと思います。これは、高次元ではさらに重要です。

于 2013-12-27T10:54:37.633 に答える
3

ラムダの主な用途は、単純なコールバック関数と、関数を引数として必要とする map、reduce、filter です。リスト内包表記が標準になり、次のように追加が許可されます。

x = [f for f in range(1, 40) if f % 2]

ラムダを日常的に使用する実際のケースを想像するのは困難です。その結果、ラムダを避け、ネストされた関数を作成することをお勧めします。

于 2008-09-25T19:13:39.320 に答える
3

ラムダの重要な制限は、式以外のものを含めることができないことです。defラムダ式がed 関数ほどリッチな本体を持つことはできないため、些細な副作用以外に何かを生成することはほぼ不可能です。

そうは言っても、Lua は私のプログラミング スタイルに無名関数の広範な使用に影響を与え、私のコードには無名関数が散らばっています。その上、リスト内包表記やジェネレーターを考慮しない方法で、マップ/リデュースを抽象演算子として考える傾向があります。これらの演算子を使用して実装の決定を明示的に延期する場合とほとんど同じです。

編集:これはかなり古い質問であり、この問題に関する私の意見は多少変わりました。

まず、私はlambda式を変数に代入することに強く反対しています。Pythonにはそのための特別な構文があるため(ヒント、def)。それに加えて、ラムダの使用の多くには、名前がなくても、定義済みの (そしてより効率的な) 実装があります。たとえば、問題の例は、または(1).__add__で囲む必要なく、単に に省略できます。その他の多くの一般的な用途は、 、およびモジュールの組み合わせで満たすことができます。lambdadefoperatoritertoolsfunctools

于 2009-06-17T00:02:38.453 に答える
1

私が見つけたラムダの用途の 1 つは、デバッグ メッセージです。

ラムダは遅延評価できるため、次のようなコードを作成できます。

log.debug(lambda: "this is my message: %r" % (some_data,))

おそらく高価な代わりに:

log.debug("this is my message: %r" % (some_data,))

これは、現在のログ レベルが原因でデバッグ コールが出力を生成しない場合でも、フォーマット文字列を処理します。

もちろん、説明どおりに機能するには、使用中のロギング モジュールがラムダを「遅延パラメーター」としてサポートする必要があります (私のロギング モジュールと同様)。

同じ考え方は、オンデマンドのコンテンツ価値創造のための遅延評価の他のケースにも適用できます。

たとえば、次のカスタム三項演算子:

def mif(condition, when_true, when_false):
    if condition:
         return when_true()
    else:
         return when_false()

mif(a < b, lambda: a + a, lambda: b + b)

それ以外の:

def mif(condition, when_true, when_false):
    if condition:
         return when_true
    else:
         return when_false

mif(a < b, a + a, b + b)

ラムダを使用すると、条件によって選択された式のみが評価され、ラムダを使用しないと両方が評価されます。

もちろん、ラムダの代わりに単純に関数を使用することもできますが、短い式ではラムダの方が (c) リーンです。

于 2015-10-21T21:37:03.317 に答える
1

ラムダをローカルスコープの変数に割り当てるだけなら、より読みやすく、将来的により簡単に拡張できるため、 def を使用することもできます。

fun = lambda a, b: a ** b # a pointless use of lambda
map(fun, someList)

また

def fun(a, b): return a ** b # more readable
map(fun, someList)
于 2008-11-18T07:19:32.897 に答える
0

私はノスクロに同意します。ところで、use once, throw away関数を使用しても、ほとんどの場合、operator モジュールから何かを使用したいだけです。

例:

このシグネチャを持つ関数があります: myFunction(data, callback function)。

2 つの要素を追加する関数を渡したいとします。

ラムダの使用:

myFunction(data, (lambda x, y : x + y))

pythonic の方法:

import operator
myFunction(data, operator.add)

もちろん、これは単純な例ですが、list と dict のアイテム setter/getter など、operator モジュールが提供するものはたくさんあります。すごくかっこいい。

于 2008-09-25T20:26:14.777 に答える
-2

ラムダは、新しい関数を生成するのに役立ちます。

>>> def somefunc(x): return lambda y: x+y
>>> f = somefunc(10)
>>> f(2)
12
>>> f(4)
14
于 2009-04-25T08:35:43.980 に答える