E731ラムダ式を割り当てないで、defを使用してください


193

ラムダ式を使用するたびに、このpep8警告が表示されます。ラムダ式はお勧めできませんか?なぜではないのですか?


4
わかりやすくするために、質問は自動チェックインのメッセージflake8flake8.pycqa.org)に言及しています
rakslice

回答:


229

実行しているPEP-8の推奨事項は次のとおりです。

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

はい:

def f(x): return 2*x 

番号:

f = lambda x: 2*x 

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

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

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

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

一般に、これを行うことに対する主な議論は、defステートメントによってコードの行数が増えることです。それに対する私の主な反応は次のとおりです。はい、それで結構です。あなたがコードゴルフをしているのでない限り、行数を最小限に抑えることはあなたがすべきことではありません。


5
それがもっと悪いのかわかりません。トレースバックには、誤った行番号とソースファイルが含まれます。一方は「f」と言うかもしれませんが、もう一方は「ラムダ」と言うかもしれません。ラムダエラーは、単一文字の関数名でも名前の付いていない長い名前でもないため、スキャンが簡単なのでしょうか?
g33kz0r 2015

4
@ g33kz0rええ、確かに、コードの残りの部分の品質が悪くなると想定している場合、次の規則はあまり役に立ちません。一般的に、いいえ、それは世界の終わりではありませんが、それはまだ悪い考えです。
Gareth Latty、2015

39
この回答はあまり役に立ちませんdef。PEP8チェッカーを使用して推奨されるアプローチを実行すると、が得られE704 multiple statements on one line (def)、2行に分割すると、次のようになりますE301 expected 1 blank line, found 0:-/
Adam Spiers

4
分割すべきだと思う。私のポイントは、a)上記の回答のコードで分割されていないため、E704が発生すること、およびb)分割する場合、E301を回避するには、その上に醜い空白行が必要です。
Adam Spiers、2015

3
純粋な関数(副作用なし)を強調したい場合はラムダを使用し、2つの場所で同じ関数を使用する必要がある場合もあります。だから私はこの慣習を無視します。
manu 2016年

119

ここに話があります、私は私が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を持たない関数について文句を言います。

私の意見では、このルールは、それが理にかなっている場合は避けて違反する方がよいと思います。


13
a = [x + offset for x in simple_list]。使用する必要はありませんmapし、lambdaここに。
ジョージー

8
@Georgyポイントはx + offset、コードの複数行を変更せずに更新できる抽象化された場所に部分を移動することであったと思います。あなたが述べたようにリスト内包表記を使用しても、x + offsetそれらを含むコードの2行がまだリスト内包表記に含まれている必要があります。著者が望むとおりにそれらを引き出すためには、defまたはが必要lambdaです。
ジュリアン

1
@Julian別にdefしてlambda1も使用することができfunctools.partialf = partial(operator.add, offset)当時とa = list(map(f, simple_list))
ジョージー

どうですかdef f(x): return x + offset(つまり、単一の行で定義された単純な関数)?少なくともflake8を使用すると、空白行に関する不満はありません。
DocOc

1
:あなたは、ネストされた理解を使用することができますいくつかのケースでは@Juliana, b = [[x + offset for x lst] for lst in (simple_list, another_simple_list)]
wjandrea

24

Lattywareは完全に正しい:基本的にPEP-8は次のようなことを避けて欲しい

f = lambda x: 2 * x

代わりに使用

def f(x):
    return 2 * x

ただし、最近のバグレポート(2014年8月)で対処されているように、次のようなステートメントが準拠しています。

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

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


8
を使用している場合でもdef、PEP8チェッカーはと文句を言うE301 expected 1 blank line, found 0ため、その前に醜い空白行を追加する必要があります。
Adam Spiers、

1

また、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はまだ存在していません。したがって、クラスから参照することもできません。


次のようalso_not_reachableにマッピング定義で参照できますSomeClass.also_not_reachable
yaccz

1
ここで何をしようとしているのかわかりません。私の場合、関数名はすべてf2.7と3.5の両方と同じくらい到達可能です
Eric

いいえ、ラムダ関数を除くすべての関数には、クラス本体内から到達できません。some_mappingオブジェクトでこれらの関数の1つにアクセスしようとすると、AttributeError:タイプオブジェクト「SomeClass」に属性「...」がありません。
simP

3
@simPすべてに完全にアクセスできます。オブジェクトが含まれているオブジェクト@staticmethodと含まれて@classmethodいないオブジェクトSomeClass.also_not_reachable(区別できる名前が必要です)。クラスメソッドからそれらにアクセスする必要がある場合は、次を使用してくださいself.also_not_reachable
ababak

@simP多分あなたはあなたの*not_reachableメソッドの名前をnot_as_easily_reachable_from_class_definition_as_a_lambdaxDに変えるべきです
Romain Vincent
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.