E731 bir lambda ifadesi atamaz, bir def kullanın


193

Lambda ifadeleri kullandığımda bu pep8 uyarısını alıyorum. Lambda ifadeleri önerilmez mi? Değilse neden?


4
Anlaşılır olması için soru, otomatik check-in flake8( flake8.pycqa.org ) mesajı
rakslice

Yanıtlar:


231

Karşılaştığınız PEP-8'deki öneri :

Lambda ifadesini doğrudan bir ada bağlayan atama ifadesi yerine her zaman bir def ifadesi kullanın.

Evet:

def f(x): return 2*x 

Hayır:

f = lambda x: 2*x 

İlk form, sonuçta ortaya çıkan işlev nesnesinin adının, genel '<lambda>' yerine özellikle 'f' olduğu anlamına gelir. Bu, genel olarak izlemeler ve dize gösterimleri için daha kullanışlıdır. Atama ifadesinin kullanımı, bir lambda ifadesinin açık bir def ifadesi üzerinden sunabileceği tek avantajı ortadan kaldırır (yani, daha büyük bir ifadenin içine gömülebilir)

Adlara lambdas atamak temel olarak sadece işlevselliğini çoğaltır def- ve genel olarak, karışıklığı önlemek ve netliği artırmak için tek bir yol yapmak en iyisidir.

Lambda için yasal kullanım durumu, bir işlevi atamadan kullanmak istediğiniz yerdir, örneğin:

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

Genel olarak, bunu yapmamaya yönelik ana argüman, defifadelerin daha fazla kod satırına neden olacağıdır. Buna benim ana cevabım: evet, ve bu iyi. Kod golf yapmadığınız sürece, çizgi sayısını en aza indirmek yapmanız gereken bir şey değildir: kısaca netleşin.


5
Nasıl daha kötü olduğunu görmüyorum. Geri izleme hala hatalı satır numarasını ve kaynak dosyasını içerecektir. Biri "f", diğeri "lambda" der. Belki lambda hatasını taramak daha kolaydır, çünkü tek karakterli bir işlev adı ya da kötü adlandırılmış uzun bir isim değildir?
g33kz0r

4
@ g33kz0r Elbette, kodunuzun geri kalanının kalitesinin kötü olacağını varsayarsanız, aşağıdaki sözleşmeler size fazla bir şey kazandırmaz. Genel olarak, hayır, bu dünyanın sonu değil, ama yine de kötü bir fikir.
Gareth Latty

39
Bu cevap çok yararlı değildir, çünkü defPEP8 denetleyicisi aracılığıyla önerilen önerilen yaklaşımı çalıştırırken, alırsınız E704 multiple statements on one line (def)ve iki satıra böldüğünüzde E301 expected 1 blank line, found 0: - /
Adam Spires

4
Ayrılması gerektiğine katılıyorum. Benim puanlarım: a) yukarıdaki yanıt kodunda bölünmemiş, E704'e neden oluyor ve b) bölerseniz, E301'i önlemek için üzerinde çirkin boş bir çizgiye ihtiyacınız var.
Adam Spires

3
Saf bir işlevi vurgulamak istediğimde lambdas kullanıyorum (yan etki yok) ve bazen aynı işlevi iki yerde kullanmak zorundayım, yani groupby ve birlikte sıralamak. Bu sözleşmeyi görmezden geliyorum.
Manu

119

İşte hikaye, iki kez kullandığım basit bir lambda fonksiyonum vardı.

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

Bu sadece temsil için, bunun birkaç farklı versiyonu ile karşılaştım.

Şimdi, şeyleri KURU tutmak için, bu ortak lambda'yı tekrar kullanmaya başlarım.

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

Bu noktada benim kod kalite denetleyicisi lambda adlı bir işlev olmaktan şikayet ediyor, bu yüzden bir işleve dönüştürmek.

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

Şimdi denetleyici, bir işlevin önce ve sonra bir satır boşluk ile sınırlandırılması gerektiğinden şikayet ediyor.

def f(x):
    return x + offset

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

Burada, okunabilirlikte bir artış ve pitonik olarak bir artış olmadan orijinal 2 satır yerine 6 kod satırımız var. Bu noktada kod denetleyicisi fonksiyonun docstrings'e sahip olmamasından şikayet eder.

Bence bu kural mantıklı olduğunda kaçınılmalı ve kırılmalıdır, kararınızı kullanın.


13
a = [x + offset for x in simple_list]. Kullanmaya gerek yok mapve lambdaburada.
Georgy

8
@Georgy Bence nokta x + offsetbirden fazla kod satırı değiştirmeden güncellenebilir soyutlanmış bir yere taşımak olduğuna inanıyorum . Bahsettiğiniz gibi liste kavrayışları ile, x + offsetşimdi liste kavrayışlarında olacaklarını içeren iki kod satırına ihtiyacınız olacaktır. Bunları yazarın istediği gibi çıkarmak için bir defya da ihtiyacınız olacaktır lambda.
Julian

1
@Julian defve functools.partial : ve sonra lambdada kullanabilirsiniz . f = partial(operator.add, offset)a = list(map(f, simple_list))
Georgy

Peki ya def f(x): return x + offset(yani, tek bir satırda tanımlanan basit bir fonksiyon)? En azından flake8 ile boş satırlardan şikayet alamıyorum.
DocOc

1
@Julian Bazı durumlarda iç içe bir anlayış kullanabilirsiniz:a, b = [[x + offset for x lst] for lst in (simple_list, another_simple_list)]
wjandrea

24

Lattyware kesinlikle doğru: Temelde PEP-8 gibi şeylerden kaçınmanızı istiyor

f = lambda x: 2 * x

ve bunun yerine kullan

def f(x):
    return 2 * x

Ancak, son bir hata raporunda (Ağustos 2014) ele alındığı gibi, aşağıdaki gibi ifadeler artık uyumludur:

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

PEP-8 denetleyicim bunu henüz doğru bir şekilde uygulamadığından şimdilik E731'i kapattım.


8
Kullanırken bile def, PEP8 denetleyicisi şikayetçi olduğundan E301 expected 1 blank line, found 0, bundan önce çirkin boş bir satır eklemeniz gerekir.
Adam Spires

1

Ayrıca def (ined) işlevini kullanmanın bile imkansız olduğu bir durumla karşılaştım.

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},
  }

Bu durumda, gerçekten sınıfa ait bir harita yapmak istedim. Eşlemedeki bazı nesnelerin aynı işleve ihtiyacı vardı. Adlandırılmış bir işlevi sınıfın dışına koymak mantıksız olurdu. Sınıf gövdesi içinden bir yönteme (statik yöntem, sınıf yöntemi veya normal) başvurmak için bir yol bulamadım. Kod çalıştırıldığında SomeClass henüz mevcut değil. Yani sınıftan bahsetmek de mümkün değil.


also_not_reachableEşleme tanımındaSomeClass.also_not_reachable
yaccz

1
Burada hangi noktayı ifade etmeye çalıştığınızı bilmiyorum. İşlev adlarınızın her biri fbenim için hem 2.7 hem de 3.5'te olduğu gibi ulaşılabilir
Eric

Hayır, lambda işlevi hariç tüm işlevlere Sınıf gövdesinden erişilemez. Some_mapping nesnesindeki bu işlevlerden birine erişmeye çalışırsanız, AttributeError: type nesnesi 'SomeClass' özelliğinin '...' özelliği yoktur.
simP

3
@simP hepsi mükemmel bir şekilde erişilebilir. Bir nesneye sahip olan @staticmethodve @classmethodbir nesneye ihtiyaç duymayanlar, sadece SomeClass.also_not_reachable(farklı isimlere ihtiyaç duysalar da). Onlara sınıf yöntemlerinden erişmeniz gerekiyorsa sadece kullanınself.also_not_reachable
ababak

@simP belki *not_reachableyöntemlerinizi not_as_easily_reachable_from_class_definition_as_a_lambdaxD olarak değiştirmelisiniz
Romain Vincent
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.