Всегда используйте оператор def вместо оператора присваивания, который связывает лямбда-выражение непосредственно с именем.
Да:
def f(x):return2*x
Нет:
f =lambda x:2*x
Первая форма означает, что имя результирующего функционального объекта определенно 'f' вместо общего '<lambda>'. Это более полезно для трассировок и строковых представлений в целом. Использование оператора присваивания исключает единственное преимущество, которое лямбда-выражение может предложить по сравнению с явным оператором def (то есть то, что оно может быть встроено в большее выражение)
Присвоение лямбды именам в основном просто дублирует функциональность def - и вообще, лучше всего сделать что-то одним способом, чтобы избежать путаницы и повысить ясность.
Законный вариант использования лямбды - это тот случай, когда вы хотите использовать функцию без ее назначения, например:
sorted(players, key=lambda player: player.rank)
В общем, главный аргумент против этого заключается в том, что defоператоры приведут к большему количеству строк кода. Мой главный ответ на это будет: да, и это хорошо. Если вы не занимаетесь кодовым гольфом, то минимизировать количество линий - это не то, что вам следует делать: переходите к ясному сокращению.
Я не вижу, как это хуже. Трассировка по-прежнему будет содержать номер строки и исходный файл. Один может сказать «f», тогда как другой говорит «лямбда». Может быть, лямбда-ошибку легче сканировать, потому что это не односимвольное имя функции или длинное имя с плохим именем?
g33kz0r
4
@ g33kz0r Ну, конечно, если вы предполагаете, что остальная часть вашего кода будет плохого качества, следующие соглашения не принесут вам большой пользы. В общем, нет, это не конец света, но это все еще плохая идея.
Гарет Латти
40
Этот ответ не очень полезен, потому что при запуске предложенного подхода с использованием defпроверки PEP8 вы получаете E704 multiple statements on one line (def), а если вы разбиваете его на две строки, вы получаете E301 expected 1 blank line, found 0: - /
Adam Spiers
4
Я согласен, что это должно быть разделено. Мои соображения заключались в том, что а) он не разделен в приведенном выше коде ответа, вызывая E704, и б) если вы разбили его, вам нужна ужасная пустая строка над ним, чтобы избежать E301.
Адам Спайерс
3
Я использую лямбду, когда хочу подчеркнуть чистую функцию (без побочных эффектов), и иногда мне приходится использовать одну и ту же функцию в двух местах, то есть группировать и сортировать вместе. Поэтому я игнорирую это соглашение.
Ман
120
Вот история, у меня была простая лямбда-функция, которую я использовал дважды.
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)
Теперь контролер жалуется, что функция должна быть ограничена одной пустой строкой до и после.
def f(x):return x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)
Здесь у нас теперь есть 6 строк кода вместо исходных 2 строк без увеличения читабельности и увеличения числа пифонов. В этот момент программа проверки кода жалуется на то, что функция не имеет строк документации.
По моему мнению, это правило лучше избегать и нарушать, когда оно имеет смысл, используйте свое суждение.
a = [x + offset for x in simple_list], Не нужно использовать mapи lambdaздесь.
Георгий
9
@ Георгий Я считаю, что цель состояла в том, чтобы переместить x + offsetчасть в абстрактное место, которое можно обновить без изменения более чем одной строки кода. Как вы уже упоминали, со списочными пониманиями вам по-прежнему понадобятся две строки кода, которые содержат x + offsetих, которые теперь будут в списочных пониманиях. Чтобы вытащить их так, как хотел автор, вам понадобится defили lambda.
Джулиан
1
@Julian Помимо defи lambdaможно также использовать functools.partial : f = partial(operator.add, offset)а затем a = list(map(f, simple_list)).
Георгий
Как насчет def f(x): return x + offset(то есть, простая функция, определенная в одной строке)? По крайней мере с flake8 я не получаю жалоб на пустые строки.
DocOc
1
@Julian В некоторых случаях вы можете использовать вложенное понимание:a, 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):return2* x
Однако, как указано в недавнем отчете об ошибках (август 2014 г.), такие утверждения, как следующие, теперь соответствуют:
a.f =lambda x:2* x
a["f"]=lambda x:2* x
Поскольку моя программа проверки PEP-8 еще не реализовала это правильно, я на время отключил E731.
Даже при использовании defпрограмма проверки PEP8 жалуется E301 expected 1 blank line, found 0, поэтому вам нужно добавить некрасивую пустую строку перед ней.
Адам Спирс
1
Я также столкнулся с ситуацией, в которой было даже невозможно использовать функцию def (ined).
classSomeClass(object):# pep-8 does not allow this
f =lambda x: x +1# NOQAdef not_reachable(self, x):return x +1@staticmethoddef also_not_reachable(x):return x +1@classmethoddef also_not_reachable(cls, x):return x +1
some_mapping ={'object1':{'name':"Object 1",'func': f},'object2':{'name':"Object 2",'func': some_other_func},}
В этом случае я действительно хотел сделать отображение, которое принадлежало классу. Некоторые объекты в отображении нуждались в той же функции. Было бы нелогично помещать именованную функцию вне класса. Я не нашел способ ссылаться на метод (статический метод, метод класса или обычный) изнутри тела класса. SomeClass еще не существует, когда код выполняется. Так что ссылаться на него из класса тоже невозможно.
Вы можете сослаться also_not_reachableв определении на карту какSomeClass.also_not_reachable
yaccz
1
Я не знаю, что вы пытаетесь сделать здесь. Каждое из ваших имен функций fдля меня так же доступно, как и в 2.7, и в 3.5
Эрик
Нет, все функции, кроме лямбда-функции, недоступны изнутри тела класса. Вы получите объект AttributeError: type «SomeClass» не имеет атрибута «...», если попытаетесь получить доступ к одной из этих функций в объекте some_mapping.
СимП
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
flake8
( flake8.pycqa.org )Ответы:
Рекомендация в PEP-8, с которой вы сталкиваетесь:
Присвоение лямбды именам в основном просто дублирует функциональность
def
- и вообще, лучше всего сделать что-то одним способом, чтобы избежать путаницы и повысить ясность.Законный вариант использования лямбды - это тот случай, когда вы хотите использовать функцию без ее назначения, например:
В общем, главный аргумент против этого заключается в том, что
def
операторы приведут к большему количеству строк кода. Мой главный ответ на это будет: да, и это хорошо. Если вы не занимаетесь кодовым гольфом, то минимизировать количество линий - это не то, что вам следует делать: переходите к ясному сокращению.источник
def
проверки PEP8 вы получаетеE704 multiple statements on one line (def)
, а если вы разбиваете его на две строки, вы получаетеE301 expected 1 blank line, found 0
: - /Вот история, у меня была простая лямбда-функция, которую я использовал дважды.
Это только для представления, я столкнулся с несколькими различными версиями этого.
Теперь, чтобы сохранить вещи СУХОЙ, я начинаю использовать эту обычную лямбду.
В этот момент моя программа проверки качества кода жалуется на то, что лямбда является именованной функцией, поэтому я преобразую ее в функцию.
Теперь контролер жалуется, что функция должна быть ограничена одной пустой строкой до и после.
Здесь у нас теперь есть 6 строк кода вместо исходных 2 строк без увеличения читабельности и увеличения числа пифонов. В этот момент программа проверки кода жалуется на то, что функция не имеет строк документации.
По моему мнению, это правило лучше избегать и нарушать, когда оно имеет смысл, используйте свое суждение.
источник
a = [x + offset for x in simple_list]
, Не нужно использоватьmap
иlambda
здесь.x + offset
часть в абстрактное место, которое можно обновить без изменения более чем одной строки кода. Как вы уже упоминали, со списочными пониманиями вам по-прежнему понадобятся две строки кода, которые содержатx + offset
их, которые теперь будут в списочных пониманиях. Чтобы вытащить их так, как хотел автор, вам понадобитсяdef
илиlambda
.def
иlambda
можно также использовать functools.partial :f = partial(operator.add, offset)
а затемa = list(map(f, simple_list))
.def f(x): return x + offset
(то есть, простая функция, определенная в одной строке)? По крайней мере с flake8 я не получаю жалоб на пустые строки.a, b = [[x + offset for x lst] for lst in (simple_list, another_simple_list)]
Lattyware абсолютно прав: в основном PEP-8 хочет, чтобы вы избегали таких вещей, как
и вместо этого использовать
Однако, как указано в недавнем отчете об ошибках (август 2014 г.), такие утверждения, как следующие, теперь соответствуют:
Поскольку моя программа проверки PEP-8 еще не реализовала это правильно, я на время отключил E731.
источник
def
программа проверки PEP8 жалуетсяE301 expected 1 blank line, found 0
, поэтому вам нужно добавить некрасивую пустую строку перед ней.Я также столкнулся с ситуацией, в которой было даже невозможно использовать функцию def (ined).
В этом случае я действительно хотел сделать отображение, которое принадлежало классу. Некоторые объекты в отображении нуждались в той же функции. Было бы нелогично помещать именованную функцию вне класса. Я не нашел способ ссылаться на метод (статический метод, метод класса или обычный) изнутри тела класса. SomeClass еще не существует, когда код выполняется. Так что ссылаться на него из класса тоже невозможно.
источник
also_not_reachable
в определении на карту какSomeClass.also_not_reachable
f
для меня так же доступно, как и в 2.7, и в 3.5@staticmethod
и@classmethod
не нуждается в объекте, простоSomeClass.also_not_reachable
(хотя им нужны отличительные имена). Если вам нужен доступ к ним из методов класса, просто используйтеself.also_not_reachable
*not_reachable
методы вnot_as_easily_reachable_from_class_definition_as_a_lambda
xD