Soru Bir listenin boş olup olmadığını nasıl kontrol ederim?


Örneğin, aşağıdakileri geçtiyse:

a = []

Nasıl olup olmadığını görmek için nasıl kontrol ederim a boş?


2729
2017-09-10 06:20


Menşei




Cevaplar:


if not a:
  print("List is empty")

Boş listenin örtülü booleanitesini kullanmak oldukça pythonic.


3907
2017-09-10 06:28



Şeytanın avukatını oynamak. Neden bu deyim pythonic olarak kabul edilir anlamıyorum. 'Açık, daha sonra üstü kapalı', doğru mu? Bu kontrol, kontrol edilen şey hakkında çok açık görünmüyor. - James McMahon
@JamesMcMahon - açıklık ve tip esnekliği arasındaki bir trade-off. Genel olarak, "açık" olmak "büyülü" şeyler yapmamak anlamına gelir. Öte yandan, "ördek yazmak", türleri açıkça kontrol etmek yerine, daha genel arayüzlerle çalışmak anlamına gelir. çok şey gibi if a == [] belirli bir türü zorlamak() == [] olduğu False). Burada genel bir fikir birliği, ördek tipi yazmanın kazanacağına benziyor. __nonzero__ boşluğu test etmek için arayüz docs.python.org/reference/datamodel.html#object.__nonzero__) - andrew cooke
Bu Programlama Önerileri bölümünde yer almaktadır PEP 8: "Diziler, (dizeler, listeler, kopyalar) için boş dizilerin yanlış olduğunu kullanın." - abarnert
ValueError: Birden fazla öğe içeren bir dizinin gerçek değeri belirsizdir. A.any () veya a.all () kullanın. Dizide bir şey olduğunda bu hatayı görüyorum - PirateApp
@PireattApp, Numpy kullanıyor olmalısınız. Düzenli dizilerden bahsediyorlar. Numpy için belki 'Yok değil' kullanmak ister misiniz? - Sam Bobel


Bunu yapmanın pythonik yolu PEP 8 stil rehberi (nerede Evet “tavsiye edilir” anlamına gelir ve Yok hayır “önerilmez” anlamına gelir:

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

Evet: if not seq:
     if seq:

Yok hayır:  if len(seq):
     if not len(seq):

865
2017-09-10 10:33



Sinyal vermek isterseniz ikinci yol daha iyi görünüyor seq bir çeşit liste benzeri nesne olması bekleniyor. - BallpointBen
Pythonism savunucularının söyleyebildiği @BallpointBen, değişkenin adlandırıldığı şekilde, dolaylı olarak ima edilmeli. - Aalok


Ben açıkça tercih ederim:

if len(li) == 0:
    print('the list is empty')

Bu şekilde% 100 net li bir sıra (liste) ve boyutunu test etmek istiyoruz. Benim sorunum if not li: ... yanlış izlenim veriyor ki li bir boole değişkeni.


519
2017-09-05 00:30



Listenin yanlış olup olmadığını kontrol etmek yerine, listenin uzunluğunun sıfıra eşit olup olmadığını kontrol etmek çirkin ve unpythonic. Python'a aşina olan herkes düşünmeyecek li bir bool ve hiç umursamıyorum. Önemliyse, daha fazla kod değil, bir yorum eklemelisiniz. - Carl Smith
Bu, çoğu zaman daha yavaş olan ve her zaman daha az okunabilir IMHO olan gereksiz yere hassas bir test gibi görünüyor. Boş bir şeyin boyutunu kontrol etmek yerine, neden boş olup olmadığını kontrol etmiyorsun? - John B
Her neyse, bu kötü (ve Python gibi güçlü deyimleri olan bir dilde deyimleri ihlal etmek genelde kötüdür) nedeni, okuyucuya belirli bir nedenden dolayı uzunluğu özellikle kontrol ettiğinizi bildirmesidir (örn. None veya 0 geçmek yerine bir istisna geliştirmek için). Yani, hiçbir sebepten ötürü yaptığınız zaman, bu yanıltıcıdır - ve aynı zamanda kodunuzda olduğu anlamına da gelir. yapar ayrımı yapması gerekiyor, ayrım görünmez çünkü “kurt ağlamışsın” kaynağın geri kalanında. - abarnert
Bence bu kodun gereksiz yere uzatılması. Aksi halde, neden daha "açık" olmasın if bool(len(li) == 0) is True:? - augurar
@Jabba olacak O (1) Birçok durumda (yerleşik veri türleriyle çalıştığınız yerler), ancak buna güvenemezsiniz. Bu mülke sahip olmayan özel bir veri türü ile çalışıyor olabilirsiniz. Bu kodu yazdıktan sonra, bu özel veri türünü daha sonra eklemeyi de isteyebilirsiniz. - ralokt


Diğer insanlar soruyu sadece listelerin ötesinde genelleştiriyor gibi görünüyor, bu yüzden birçok kişinin kullanabileceği farklı bir sıralama türü için bir uyarı ekleyeceğimi düşündüm, özellikle de bu "python testi boş dizisi" için ilk google vuruşu olduğundan .

Diğer yöntemler numpy dizileri için çalışmıyor

Sayısal dizilerle dikkatli olmanız gerekir, çünkü lists veya diğer standart kaplar, numpy dizileri için başarısız olur. Aşağıda nedenini açıklarım ama kısaca tercih edilen yol kullanmak size.

"Pythonic" yolu çalışmıyor: Bölüm 1

"Pythonic" yolu numpy dizileriyle başarısız olur, çünkü numpy diziyi bir dizi diziye çevirmeye çalışır. bools ve if x tüm bunları değerlendirmeye çalışır boolBir kerede toplam gerçek değer için. Ama bu bir anlam ifade etmiyor. ValueError:

>>> x = numpy.array([0,1])
>>> if x: print("x")
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

"Pythonic" yolu çalışmıyor: Bölüm 2

Ama en azından yukarıdaki davada bunun başarısız olduğunu söyler. Tam olarak bir eleman ile bir numpy dizisi varsa, if deyim, bir hata almamanız anlamında "çalışır". Ancak, eğer bu bir eleman olursa 0 (veya 0.0veya false...) if ifadesi yanlış sonuçlanacak false:

>>> x = numpy.array([0,])
>>> if x: print("x")
... else: print("No x")
No x

Ama açıkça x var ve boş değil! Bu sonuç istediğin gibi değil.

kullanma len beklenmedik sonuçlar verebilir

Örneğin,

len( numpy.zeros((1,0)) )

dizi sıfır öğeye sahip olsa bile 1 değerini döndürür.

Numpythonic yolu

Açıklandığı gibi scipy SSS, numpy dizisi olduğunu bildiğiniz her durumda doğru yöntem kullanmaktır if x.size:

>>> x = numpy.array([0,1])
>>> if x.size: print("x")
x

>>> x = numpy.array([0,])
>>> if x.size: print("x")
... else: print("No x")
x

>>> x = numpy.zeros((1,0))
>>> if x.size: print("x")
... else: print("No x")
No x

Bunun bir şey olup olmadığından emin değilseniz list, numpy dizisi veya başka bir şeyle, bu yaklaşımı cevap @dubiousjim verir Her test için doğru testin yapıldığından emin olmak için. Çok "pythonic" değil, fakat bu mantık, en azından bu anlamda pythonisiteyi bilerek kırdı.

Girişin boş olup olmadığını kontrol etmekten ve indeksleme veya matematik işlemleri gibi diğer sayısal özelliklerden daha fazlasını yapmanız gerekiyorsa, girişi zorlamak için muhtemelen daha verimli (ve kesinlikle daha yaygın) olmak numpy dizisi. Bunu hızlıca yapmak için birkaç güzel fonksiyon var - en önemlisi numpy.asarray. Bu sizin girişinizi alır, zaten bir dizi ise hiçbir şey yapmaz ya da bir liste, tuple vb. İse girişinizi bir diziye sarar ve isteğe bağlı olarak sizin seçtiğiniz birime dönüştürür. dtype. Bu yüzden, olabildiğince hızlı ve girişin numpy dizisi olduğunu varsaymanızı sağlar. Bir diziye dönüştürme işlemi, akımın dışına geri getirmeyeceğinden, genellikle yalnızca aynı adı kullanırız. kapsam:

x = numpy.asarray(x, dtype=numpy.double)

Bu yapacak x.size Bu sayfada gördüğüm her durumda çalışmayı kontrol et.


209
2018-02-21 16:48



Bunun Python'da bir kusur olmadığını, daha ziyade kasıtlı bir sözleşme kırılması olduğunu belirtmekte fayda var. numpy - numpy Çok özel bir kullanım durumu olan bir kütüphanedir ve bir dizideki gerçekliğin konteynırlar için Python standardına göre farklı bir 'doğal' tanımına sahiptir. Bu durumda, bu durumda optimize etmek için mantıklı. pathlib kullanımları / yerine yolları birleştirmek için + - standart dışı, ancak bağlamda mantıklı. - Gareth Latty
Kabul. Benim düşüncem, bu yazının, hem çok yaygın hem de yazgısını yazmak için ördek seçimi yapmayı tercih ettiğini hatırlamak önemlidir. if x ve len(x) deyimler - ve bazen bu kırılmayı tespit etmek ve hata ayıklamak çok zor olabilir. - Mike
Bilmiyorum, benim için, len (x) denilen bir yöntem varsayımlar nedeniyle dizi uzunluğunu döndürmezse, adı kötü tasarlanmıştır. - Dalton
Bu sorunun numpy dizileri ile ilgisi yok - ppperry
@ppperry Evet, asıl soru Numpy dizileriyle ilgili değildi, ancak bu ve muhtemelen ördek tipi argümanlar ile çalışırken, bu soru çok alakalı hale geliyor. - peterhil


Boş bir liste, gerçek değer testinde yanlış kabul edilir (bkz. python belgeleri):

a = []
if a:
     print "not empty"

@Daren Thomas

DÜZENLEME: Testlere karşı bir başka nokta   boş liste olarak yanlış: ne hakkında   polimorfizmi? Güvenmemelisin   liste listesi. Sadece olmalı   ördek gibi kaçmak - nasıl gidiyorsun   senin duckcollection almak için quack   Hiçbir unsuru olmadığında '' False ''?

DuckCollection uygulamanız yapılmalı __nonzero__ veya __len__ yani a: problemsiz çalışır.


104
2017-09-10 06:31





Bir listenin boş olup olmadığını kontrol etmenin en iyi yolu

Örneğin, aşağıdakileri geçtiyse:

a = []

Boş olup olmadığını nasıl kontrol ederim?

Kısa cevap:

Listeyi bir boole bağlamında yerleştirin (örneğin, bir if veya while Beyan). Test edecek False eğer boşsa ve True aksi takdirde. Örneğin:

if not a:                           # do this!
    print('a is an empty list')

Otoriteye itiraz

PEP 8Python'un standart kitaplığındaki Python kodunun resmi Python stil rehberi şunları söylüyor:

Diziler, (dizeler, listeler, kopyalar) 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):

Standart kütüphane kodunun mümkün olduğunca verimli ve doğru olması gerektiğini beklemeliyiz. Ama neden bu durumda ve neden bu rehberliğe ihtiyacımız var?

açıklama

Sıklıkla Python’dan yeni tecrübeli programcılardan böyle bir kod görüyorum:

if len(a) == 0:                     # Don't do this!
    print('a is an empty list')

Ve tembel dil kullanıcıları, bunu yapmak için cazip olabilir:

if a == []:                         # Don't do this!
    print('a is an empty list')

Bunlar diğer dillerinde doğrudur. Ve bu Python'da bile anlamsal olarak doğrudur.

Ama biz bunu Python olmayan düşünürüz, çünkü Python bu semantiği doğrudan liste nesnesinin arayüzünde boole baskısı ile desteklemektedir.

İtibaren docs (ve özellikle boş listenin dahil edilmesine dikkat edin, []):

Varsayılan olarak, nesnesi tanımlanmadığı sürece bir nesne doğru kabul edilir.   ya bir __bool__() döndüren yöntem False ya da __len__() yöntem   Nesne ile çağrıldığında sıfır döner. Burada yanlış olarak kabul edilen yerleşik nesnelerin çoğu vardır:

  • yanlış olarak tanımlanan sabitler: None ve False.
  • herhangi bir sayısal türden sıfır: 0, 0.0, 0j, Decimal(0), Fraction(0, 1)
  • boş diziler ve koleksiyonlar: '', (), [], {}, set(), range(0)

Ve datamodel belgeleri:

object.__bool__(self)

Gerçek değer testi ve yerleşik operasyon uygulamak için çağrıldı bool(); geri dönmeli False veya True. Bu yöntem tanımlanmadığında,    __len__() tanımlanırsa çağrılır ve sonucu sıfırdan farklı olduğunda nesne doğru kabul edilir. Bir sınıf, ne __len__()   ne de __bool__()tüm örnekleri doğru olarak kabul edilir.

ve

object.__len__(self)

Yerleşik fonksiyonu uygulamak için denir len(). Nesnenin uzunluğunu döndürmesi gereken bir tam sayı> = 0. Ayrıca, bir __bool__() yöntemi ve __len__() yöntemi döndürür Boole bağlamında sıfır olarak kabul edilir.

Yani bunun yerine:

if len(a) == 0:                     # Don't do this!
    print('a is an empty list')

veya bu:

if a == []:                     # Don't do this!
    print('a is an empty list')

Bunu yap:

if not a:
    print('a is an empty list')

Pythonic'in neyi genellikle performansta ödüyor?

Ödüyor mu? (Eşdeğer bir işlemi gerçekleştirmek için daha az zaman daha iyidir :)

>>> import timeit
>>> min(timeit.repeat(lambda: len([]) == 0, repeat=100))
0.13775854044661884
>>> min(timeit.repeat(lambda: [] == [], repeat=100))
0.0984637276455409
>>> min(timeit.repeat(lambda: not [], repeat=100))
0.07878462291455435

Ölçek için, işte bu fonksiyonu çağırmanın ve boş bir listenin oluşturulup iade edilmesinin maliyeti, yukarıda kullanılan boşluk kontrollerinin maliyetlerinden düşebilirsiniz:

>>> min(timeit.repeat(lambda: [], repeat=100))
0.07074015751817342

Bunu görüyoruz ya yerleşik işlevle uzunluk kontrolü len nazaran 0  veya boş bir listeye karşı kontrol etmek çok belgelenen dilin yerleşik sözdizimini kullanmaktan daha az performans.

Niye ya?

İçin len(a) == 0 Kontrol:

İlk Python, dünyayı kontrol etmek için len gölgeli.

Sonra fonksiyonu çağırmalı, yük 0ve Python'da eşitlik karşılaştırması yapın (C yerine):

>>> import dis
>>> dis.dis(lambda: len([]) == 0)
  1           0 LOAD_GLOBAL              0 (len)
              2 BUILD_LIST               0
              4 CALL_FUNCTION            1
              6 LOAD_CONST               1 (0)
              8 COMPARE_OP               2 (==)
             10 RETURN_VALUE

Ve için [] == [] gereksiz bir liste oluşturmalı ve daha sonra Python'un sanal makinesinde (C'nin aksine) karşılaştırma işlemini yapmalıdır.

>>> dis.dis(lambda: [] == [])
  1           0 BUILD_LIST               0
              2 BUILD_LIST               0
              4 COMPARE_OP               2 (==)
              6 RETURN_VALUE

Listenin uzunluğu nesne örneği üstbilgisinde önbelleğe alındığından "Pythonic" yolu çok daha basit ve hızlı bir şekilde kontrol edilir:

>>> dis.dis(lambda: not [])
  1           0 BUILD_LIST               0
              2 UNARY_NOT
              4 RETURN_VALUE

C kaynağından ve dokümantasyondan kanıt

PyVarObject

Bu bir uzantısıdır PyObject bu ekler ob_size alan. Bu sadece bazı uzunluk kavramı olan nesneler için kullanılır. Bu tür genellikle Python / C API'sinde görünmez. Genişlemenin tanımladığı alanlara karşılık gelir. PyObject_VAR_HEAD makro.

İçindeki c kaynağından / Listobject.h Dahil:

typedef struct {
    PyObject_VAR_HEAD
    /* Vector of pointers to list elements.  list[0] is ob_item[0], etc. */
    PyObject **ob_item;

    /* ob_item contains space for 'allocated' elements.  The number
     * currently in use is ob_size.
     * Invariants:
     *     0 <= ob_size <= allocated
     *     len(list) == ob_size

Bunu araştırmaktan zevk aldım ve cevaplarımı toparlamak için çok zaman harcıyorum. Bir şeyleri dışarıda bıraktığımı düşünüyorsanız, lütfen yorumda bana bildirin.


83
2017-08-20 03:50



Bu IMO'nun oldukça iyi bir okuması ve değerli bir katkısıdır (sorunun ortaya çıkmasından dokuz yıl sonra cevap vermek bazı kokulara sahip olabilir, ama bu durumda en azından benim için değil). Teşekkürler Aaron. - Dilettant
@Dilettant Kokanlar, bizi daha yakından gösteren başparmak veya sezgisel kurallardır. Bazı yeni kullanıcılar temelde diğer cevapları kopyalayan geç cevaplar gönderiyor ve bu da geç cevaplar söz konusu olduğunda endişe duyduğumuz bir şey. Değer katmayan geç cevaplar Hangi Ancak oldukça hoş karşılanır - aksi takdirde Reddit gibi bir süre sonra da mesajları kapatırdık. - Aaron Hall♦


Patrick'in (kabul edildi) cevabı doğrudur: if not a: Bunu yapmak için doğru yoldur. Harley Holcombe'un cevabı bunun PEP 8 tarzı kılavuzda olduğu doğrudur. Ancak cevapların hiçbirinin açıklayamadığı şey, deyimi takip etmenin neden iyi bir fikir olduğudur. Kişisel olarak, Ruby kullanıcılarına ya da herhangi bir şeye yeteri kadar açık ya da kafa karıştırıcı olmayan bir şey bulsanız bile.

Python kodu ve Python topluluğu çok güçlü deyimlere sahiptir. Bu deyimleri takiben kodunuzu Python'da deneyimli herkes için okumayı kolaylaştırır. Ve bu deyimleri ihlal ettiğinizde, bu güçlü bir sinyal.

Olduğu doğru if not a: boş listeleri ayırt etmiyor Noneveya sayısal 0 veya boş tuples veya boş kullanıcı tarafından oluşturulmuş koleksiyon türleri veya boş kullanıcı tarafından oluşturulmuş olmayan koleksiyonlar veya boş değerlerle skaler gibi davranan tek öğe NumPy dizisi. Ve bazen önemli olmak bunun hakkında açık. Ve bu durumda, biliyorsun ne Açık olmak istiyorsan, tam olarak bunu test edebilirsin. Örneğin, if not a and a is not None:"Hiçbiri dışındaki hiçbir şey falsey" anlamına gelir. if len(a) != 0: "sadece boş diziler" anlamına gelir ve bir sıralamanın yanı sıra burada bir hata ", vb. Test etmek istediğiniz şeyi tam olarak test etmenin yanı sıra, bu da okuyucuya bu testin önemli olduğunu işaret eder.

Ama açık bir şeyiniz olmadığında, başka bir şey değil. if not a: okuyucuyu yanıltıcıdır. Olmadığı zaman önemli olan bir şeye işaret ediyorsun. (Ayrıca kodu daha az esnek veya daha yavaş ya da her neyse yapabilirsin, ama bu daha az önemli.) habitually okuyucuyu bu şekilde yanlış yönlendirin, sonra yap Bir fark yaratmanız gerekiyor, fark edilmeyecek, çünkü kodunuzun her tarafında "kurt ağlıyor" oldunuz.


82
2017-12-03 02:21