web-dev-qa-db-ja.com

E731はラムダ式を割り当てず、defを使用します

ラムダ式を使用すると、このpep8警告が表示されます。ラムダ式は推奨されませんか?そうでない場合はなぜですか?

161
Kechit Goyal

PEP-8 での推奨事項は次のとおりです。

ラムダ式を名前に直接バインドする割り当てステートメントの代わりに、常にdefステートメントを使用します。

はい:

def f(x): return 2*x 

いいえ:

f = lambda x: 2*x 

最初の形式は、結果の関数オブジェクトの名前が、一般的な「<lambda>」ではなく具体的​​に「f」であることを意味します。これは、一般的なトレースバックや文字列表現に役立ちます。割り当てステートメントを使用すると、ラムダ式が明示的なdefステートメントに対して提供できる唯一の利点がなくなります(つまり、大きな式の中に埋め込むことができます)

ラムダを名前に割り当てることは、基本的にdefの機能を複製するだけです。一般に、混乱を避けて明快さを高めるために何かを行うのが最善です。

Lambdaの正当な使用例は、関数を割り当てずに使用したい場合です。例えば:

sorted(players, key=lambda player: player.rank)

単純な操作の場合、 operatorモジュールattrgetteritemgetter およびlabmdasを頻繁に置き換えることができる methodcaller の便利なオプションを提供します属性、アイテム、メソッドの呼び出しにアクセスしているだけです。

たとえば、上記はoperator.attrgetterで次のように実行できます。

sorted(players, key=operator.attrgetter('rank'))
178
Gareth Latty

ここに物語があります、私は2回使っていた単純なラムダ関数を持っていました。

a = map(lambda x : x + offset, simple_list)
b = map(lambda x : x + offset, another_simple_list)

これは単に表現のためであり、このバージョンのいくつかの異なるバージョンに直面しています。

さて、物事を乾いた状態に保つために、この共通のラムダを再利用し始めました。

f = lambda x : x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)

この時点で、私のコード品質チェッカーは、ラムダが名前付き関数であると文句を言うので、それを関数に変換します。

def f(x):
    return x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)

現在、チェッカーは、関数が前後に1つの空白行で区切られている必要があると文句を言います。

def f(x):
    return x + offset

a = map(f, simple_list)
b = map(f, another_simple_list)

ここで、元の2行の代わりに6行のコードがあり、読みやすさの向上もPythonic性の向上もありません。この時点で、コードチェッカーはdocstringを持たない関数について文句を言います。

私の意見では、このルールは理にかなっている場合は避けるべきであり、それを破る方が賢明です。

95
iankit

Lattywareは絶対に正しい:基本的に PEP-8 は次のようなことを避けたい

f = lambda x: 2 * x

代わりに使用します

def f(x):
    return 2 * x

ただし、最近の bugreport (2014年8月)で説明されているように、次のようなステートメントは準拠しています。

a.f = lambda x: 2 * x
a["f"] = lambda x: 2 * x

私のPEP-8チェッカーはまだこれを正しく実装していないため、当分の間E731をオフにしました。

21
Elmar Peise

また、def(ined)関数を使用することさえ不可能な状況に遭遇しました。

class SomeClass(object):
  # pep-8 does not allow this
  f = lambda x: x + 1  # NOQA

  def not_reachable(self, x):
    return x + 1

  @staticmethod
  def also_not_reachable(x):
    return x + 1

  @classmethod
  def also_not_reachable(cls, x):
    return x + 1

  some_mapping = {
      'object1': {'name': "Object 1", 'func': f},
      'object2': {'name': "Object 2", 'func': some_other_func},
  }

この場合、クラスに属するマッピングを作成したかったのです。マッピング内の一部のオブジェクトには同じ機能が必要でした。名前付き関数をクラスの外部に配置するのは非論理的です。クラス本体内からメソッド(staticmethod、classmethod、またはnormal)を参照する方法を見つけていません。コードの実行時には、SomeClassはまだ存在していません。したがって、クラスからそれを参照することもできません。

2
simP