ラムダ式を使用するたびに、この pep8 警告が表示されます。ラムダ式は推奨されませんか? そうでない場合、なぜですか?
5 に答える
あなたが実行している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ステートメントによってコード行が増えるということです。それに対する私の主な反応は次のとおりです。はい、それで結構です。コードゴルフをしているのでない限り、行数を最小限に抑えることはすべきことではありません。短くするよりも明確にする必要があります。
これがストーリーです。2回使用していた単純なラムダ関数がありました。
a = map(lambda x : x + offset, simple_list)
b = map(lambda x : x + offset, another_simple_list)
これは単なる表現のためのものです。私はこれのいくつかの異なるバージョンに直面しました。
さて、物事を DRY に保つために、この共通のラムダを再利用し始めます。
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 がないことを報告します。
私の意見では、このルールは避けて、理にかなっている場合は破ったほうがよいので、あなたの判断で使用してください。
また、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 はまだ存在しません。したがって、クラスから参照することもできません。
これはクラスで機能し、ラムダ式を削除し、代わりに def を使用して、これを変更します...
def set_every(self, every: int = 1, time_unit: int = TimeUnit.Day):
every_func = lambda x: "*" if x == 1 else "*/" + str(x)
if TimeUnit.has_value(time_unit):
self.month_of_year = "*"
self.day_of_month = "*" if time_unit != TimeUnit.Day else every_func(every)
self.day_of_week = "*" if time_unit != TimeUnit.Week else every_func(every)
これで...
def set_every(self, every: int = 1, time_unit: int = TimeUnit.Day):
def every_func(x: int) -> str: return "*" if x == 1 else "*/" + str(x)
if TimeUnit.has_value(time_unit):
self.month_of_year = "*"
self.day_of_month = "*" if time_unit != TimeUnit.Day else every_func(every)
self.day_of_week = "*" if time_unit != TimeUnit.Week else every_func(every)