Pylint tarafından koşul değerlerinde len (SEQUENCE) kullanımı neden yanlış kabul edilir?


211

Bu kod snippet'i göz önüne alındığında:

from os import walk

files = []
for (dirpath, _, filenames) in walk(mydir):
    # more code that modifies files
if len(files) == 0: # <-- C1801
    return None

Pylint tarafından if ifadesi ile ilgili bu mesajla telaşlandım:

[pylint] C1801: Kullanmayın len(SEQUENCE) Koşul değeri olarak

İlk bakışta C1801 kuralı benim için çok makul gelmedi ve referans kılavuzundaki tanım bunun neden bir sorun olduğunu açıklamıyor. Aslında, düpedüz yanlış kullanım olarak adlandırır .

koşul olarak len (C1801) : Koşul değeri olarak kullanmayın len(SEQUENCE)Pylint koşullar içinde len (sekans) yanlış kullanımını tespit ettiğinde kullanılır.

Arama girişimlerim de bana daha derin bir açıklama yapamadı. Bir dizinin length özelliğinin tembel olarak değerlendirilebileceğini ve__len__ yan etkileri olacak şekilde programlanabileceğini anlıyorum, ancak bunun tek başına Pylint'in böyle bir kullanımı yanlış olarak adlandırması için yeterince sorunlu olup olmadığı tartışmalıdır. Bu nedenle, projemi kuralı göz ardı edecek şekilde yapılandırmadan önce, akıl yürütmemde bir şey eksik olup olmadığımı bilmek istiyorum.

len(SEQ)Koşul değeri olarak kullanımı ne zaman sorunludur? Pylint C1801 ile hangi önemli durumlardan kaçınmaya çalışıyor?


9
Çünkü dizinin gerçekliğini doğrudan değerlendirebilirsiniz. pylint yapmak istiyor if files:yaif not files:
Patrick Haugh

38
lençağrıldığı bağlamı bilmiyorsa, eğer uzunluğun hesaplanması tüm sekansın içinden geçmek anlamına geliyorsa, o olmalıdır; sonucun 0 ile karşılaştırıldığını bilmiyor. Boolean değerinin hesaplanması, dizinin gerçekte ne kadar uzun olduğuna bakılmaksızın, ilk öğeyi gördükten sonra durabilir. Bence pylint burada biraz düşünülüyor; Ne olduğunu her durum düşünemiyorum yanlış kullanımına lenalternatifinden daha kötü bir seçenek sadece.
chepner

2
@ E_net4 Bence PEP-8 muhtemelen başlangıç ​​için bir yer.
Patrick Haugh


6
SEQUENCES, C ++ imo gibi bir 'boş ()' veya 'isempty ()' gerektirir.
JDonner

Yanıtlar:


281

Ne zaman kullanılır len(SEQ)Koşul değeri olarak sorunludur? Pylint C1801 ile hangi önemli durumlardan kaçınmaya çalışıyor?

O değil gerçekten kullanımına sorunlu len(SEQUENCE)- bu (bkz verimli olarak olmayabilir ama chepner yorumuna ). Ne olursa olsun, Pylint kodu PEP 8 stil kılavuzuna uygunluk açısından kontrol eder .

Diziler (dizeler, listeler, tuples) için boş dizilerin yanlış olduğu gerçeğini kullanın.

Yes: if not seq:
     if seq:

No:  if len(seq):
     if not len(seq):

Diller arasında flört eden bir Python programcısı olarak, len(SEQUENCE)yapının daha okunaklı ve açık olduğunu düşünürdüm (“Açık, üstü kapalı olmak daha iyidir”). Ancak, boş bir dizinin FalseBoole bağlamında değerlendirildiği gerçeğinin kullanılması daha “Pythonic” olarak değerlendirilir.


O zaman bu iş nasıl yapılır:if len(fnmatch.filter(os.listdir(os.getcwd()), 'f_*')):
Marichyasana

@Marichyasana Sanırım böyle şeyler (teorik olarak) yazılabilir if next(iter(...), None) is not None:(dizi içeremezse None). Bu çok uzun, ama len(fnmatch...)çok uzun; her ikisinin de bölünmesi gerekir.
Kirill Bulygin

13
Ben aynı zamanda bir Python kullanıcısıyım ve sık sık "Pythonic yolu" kendi belirsizliği içinde karışık bir izlenim var izlenim var.
luqo33

3
Sadece genel bir soru, bu KEP önerileri gözden geçirilebilir mi? len(s) == 0Kanımca bence üstün olmasının bir başka nedeni de diğer sekans türleri için genellenebilir olmasıdır. Örneğin pandas.Seriesve numpy dizileri. if not s:diğer yandan değildir ve bu durumda dizilere benzer tüm olası nesne türleri için ayrı bir değerlendirme kullanmanız gerekir (örn. pd.DataFrame.empty).
Marses

2
Bu arada, hiçbir of collections.abcsınıf durum __bool__yöntemi ifade etmez. Başka bir deyişle, nasıl kullanabilir miyim emin olabiliriz bool(seq)Ben bir olduğunu biliyorum eğer collections.abc.Collection? Moreso, bazı kütüphaneler bool(collection)sınıflarını kontrol etmenin yasak olduğunu karara bağlar .
Eir Nym

42

NumPy dizilerini kullanırken aslında len (seq) kullanımının gerekli olduğunu unutmayın (sadece seq'nin bool değerini kontrol etmek yerine).

a = numpy.array(range(10))
if a:
    print "a is not empty"

bir istisna ile sonuçlanır: ValueError: Birden fazla öğeye sahip bir dizinin doğruluk değeri belirsiz. A.any () veya a.all () kullanın

Bu nedenle hem Python listelerini hem de NumPy dizilerini kullanan kodlar için C1801 mesajı yardımcı olmaktan daha azdır.


5
İfadenize katılıyorum. # 1405 numaralı sorunla birlikte , C1801'in varsayılan olarak yararlı bir şeye dönüştürüldüğünü veya devre dışı bırakıldığını görmeyi umuyorum.
E_net4 bayrakları

2
ayrıca bir dizinin belirli sayıda öğeye sahip olup olmadığını kontrol etmek işe yaramaz. Sadece en iyi durumda tamamen boş olduğunu kontrol etmek için iyidir.
PabTorre

1

Bu, pylint'te bir konuydu ve artık dikkate almıyor len(x) == 0 yanlış olarak .

Bir çıplakı len(x) koşul olarak kullanmamalısınız . Karşılaştırmak len(x)gibi, açık bir değere karşı if len(x) == 0arasındaif len(x) > 0 tamamen iyi değil PEP 8 yasaklanan olduğunu.

Gönderen PEP 8 :

# Correct:
if not seq:
if seq:

# Wrong:
if len(seq):
if not len(seq):

Not açıkça uzunluğu için test yasaklanmamıştır. Python Zen devletler:

Açık, örtük olmaktan iyidir.

Arasındaki seçim olarak if not seqve if not len(seq)hem örtük ama davranış farklıdır. Ancak if len(seq) == 0veyaif len(seq) > 0 da açık karşılaştırmalar ve birçok bağlamda doğru davranış.

Pylint'te, PR 2815 , ilk olarak 2684 numaralı sorun olarak bildirilen bu hatayı düzeltti . Şikayet etmeye devam edecek if len(seq), ancak artık şikayet etmeyecek if len(seq) > 0. PR 2019-03-19 ile birleştirildi, bu nedenle pylint 2.4 (2019-09-14 yayınlandı) kullanıyorsanız bu sorunu görmemelisiniz.


0

Pylint kodum için başarısız oldu ve araştırma beni bu gönderiye götürdü:

../filename.py:49:11: C1801: Do not use `len(SEQUENCE)` to determine if a sequence is empty (len-as-condition)
../filename.py:49:34: C1801: Do not use `len(SEQUENCE)` to determine if a sequence is empty (len-as-condition)

Bu önce kodum oldu:

def list_empty_folders(directory):
"""The Module Has Been Build to list empty Mac Folders."""
for (fullpath, dirnames, filenames) in os.walk(directory):
    if len(dirnames) == 0 and len(filenames) == 0:
        print("Exists: {} : Absolute Path: {}".format(
            os.path.exists(fullpath), os.path.abspath(fullpath)))

Bu benim kod düzeltme sonra oldu. Kullanarak int() attribute, ben Pep8 / Pylint memnun gibi görünüyor ve benim kod üzerinde olumsuz bir etkisi gibi görünmüyor:

def list_empty_folders(directory):
"""The Module Has Been Build to list empty Mac Folders."""
for (fullpath, dirnames, filenames) in os.walk(directory):
    if len(dirnames).__trunc__() == 0 and len(filenames).__trunc__() == 0:
        print("Exists: {} : Absolute Path: {}".format(
            os.path.exists(fullpath), os.path.abspath(fullpath)))

Düzeltmem

Diziye ekleyerek .__trunc__()ihtiyacı çözmüş gibi görünüyor.

Davranışta bir fark görmüyorum, ancak kimse özlediğim özellikleri biliyorsa, lütfen bana bildirin.


1
(Biraz fazla) uzunluk değerini bir tamsayıya kesen __trunc__()çıktısını çağırıyorsunuz len(seq). Sadece tiftik sebebini ele almadan tüy bırakıyor. Kabul edilen cevaptaki öneri sizin için işe yaramadı mı?
E_net4 bayraklar

Girişimlerimde değil. Artıklığı anlıyorum, ancak bu sorun github.com/PyCQA/pylint/issues/1405 & 2684'teki geliştiriciler tarafından ele alındıktan ve birleştirildikten sonra bile, pylint çalıştırırken bu bir sorun olmamalı ama Hayal gücümü güncelledikten sonra bile bu sorunu görüyorum. this worked for meTamamen uygun olmasa bile paylaşmak istedim . Ancak, len (seq) == 0 karşılaştırması yapıyorsanız gereksiz olsa bile açıklığa kavuşturmak için, trunc zaten tamsayılar olduğu için bir şey yapmak zorunda olmamalıdır. sağ?
JayRizzo

1
Tam olarak, zaten bir tamsayıdır ve __trunc__()anlamlı bir şey yapmaz. Karşılaştırmayı gereksiz olarak ifade etmediğimi, ancak bu uzunluğu kısaltmaya çalıştığımı unutmayın. Yalnızca formun bir ifadesini beklediği için uyarı kaybolur len(seq) == 0. Bu durumda tiftik if ifadesini aşağıdaki ile değiştirmenizi beklediğine inanıyorum:if not dirnames and not filenames:
E_net4 bayraklar

Doğruluk testi, __bool__fonksiyonun altta yatan sırada tanımlanmamış olması durumunda "daima doğru" olmanın istenmeyen sonuçları vardır .
Erik Aronesty
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.