E731 не назначайте лямбда-выражение, используйте def


Я получаю это предупреждение pep8 всякий раз, когда я использую лямбда-выражения. Не рекомендуется ли использовать лямбда-выражения? Если нет то почему?

5 137

5 ответов:

рекомендация PEP-8 вы бежите в это:

всегда используйте оператор def вместо оператора присваивания, который связывает лямбда-выражение непосредственно с именем.

да:

def f(x): return 2*x 

нет:

f = lambda x: 2*x 

первая форма означает, что имя в результате объект функции-это конкретно 'f' вместо общего ' '. Это более полезно для трассировки и строки представления в генеральный. Использование оператора присваивания исключает подошву преимущество лямбда-выражение может предложить над явным оператором def (т. е. что он может быть встроен в большее выражение)

назначение лямбд именам в основном просто дублирует функциональность def - и вообще, лучше всего делать что-то одним способом, чтобы избежать путаницы и повысить ясность.

законный случай использования для лямбда-это то, где вы хотите чтобы использовать функцию без ее назначения, например:

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

для простых операций, the operator модуль предоставляет некоторые полезные опции в attrgetter,itemgetter и methodcaller который часто может заменить labmdas, которые просто обращаются к атрибутам, элементам и вызывающим методам.

например, выше может быть сделано с operator.attrgetter вот так:

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

вот история, у меня была простая лямбда-функция, которую я использовал дважды.

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 линии, без увеличения читаемости и увеличения время обновления. На этом этапе средство проверки кода жалуется на то, что функция не имеет docstrings.

на мой взгляд, этого правила лучше избегать и нарушать, когда это имеет смысл, используйте свое суждение.

Lattyware абсолютно прав: в принципе PEP-8 хочет, чтобы вы избегали таких вещей, как

f = lambda x: 2 * x

и вместо того, чтобы использовать

def f(x):
    return 2 * x

однако, как указано в недавнем bugreport (Aug 2014), заявления, такие как следующие теперь совместимы:

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

Так как мой PEP-8 checker еще не реализовал это правильно, я отключил E731 на данный момент.

Я также столкнулся с ситуацией, в которой было даже невозможно использовать функцию 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 еще не существует, когда выполняется код. Так обращение к нему из класса также невозможно.

лямбды можно использовать для ленивых оценок, таким образом откладывая некоторые дорогостоящие операции до тех пор, пока их результаты не понадобятся на самом деле.

Я только что столкнулся с одним случаем (по проблеме конкуренции/практики кода), где я вычислял относительно дорогие функции pow () (относительно дорогие, поскольку вход состоял из полумиллиона тестовых случаев) для 3 разных случаев и определенных комбинаций из 3 случаев. Для ясности кода я бы вычислил все 3 случая, а затем вернул комбинацию из 3, которые были действительно необходимы для текущего запроса.

к сожалению, это генерировало TLE ("превышен лимит времени") на некоторых входах.

используя лямбды для отсрочки дорогостоящих операций pow (), я смог решить проблемы TLE, поскольку на самом деле были вызваны только вычисления, относящиеся к текущему запросу.

поэтому я думаю, что это тот случай, когда предупреждение E731 на самом деле не применимо и должно быть отключено..