Làm cách nào để kiểm tra xem danh sách có trống không?


3234

Ví dụ: nếu được thông qua như sau:

a = []

Làm thế nào để tôi kiểm tra xem nếu atrống?

Câu trả lời:


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

Sử dụng booleanness ngầm của trống listlà khá pythonic.


1130
Chơi ma quỷ ủng hộ. Tôi không hiểu tại sao thành ngữ này được coi là pythonic. 'Rõ ràng là tốt hơn sau đó ngầm', đúng không? Kiểm tra này dường như không rõ ràng về những gì đang kiểm tra.
James McMahon

222
@JamesMcMahon - đó là sự đánh đổi giữa tính linh hoạt và tính linh hoạt. nói chung, "rõ ràng" có nghĩa là không làm những điều "ma thuật". mặt khác, "gõ vịt" có nghĩa là làm việc với các giao diện chung hơn, thay vì kiểm tra rõ ràng các loại. vì vậy một cái gì đó giống như if a == []là buộc một loại cụ thể ( () == []False). Ở đây, sự đồng thuận chung dường như là việc gõ vịt sẽ thắng (thực tế, nói rằng đó __nonzero__là giao diện để kiểm tra sự trống rỗng docs.python.org/reference/datamodel.html#object.__nonzero__ )
rút ra

38
Phương pháp này không hoạt động trên các mảng numpy .. vì vậy tôi nghĩ rằng nếu len (a) == 0 thích hợp hơn cả về "gõ vịt" và nhân chứng.
Mr.WorshipMe

10
Cách chính tắc để biết một mảng trong C có trống hay không là bằng cách hủy bỏ phần tử đầu tiên và xem nó có phải là null hay không, giả sử một mảng bị chấm dứt. Mặt khác, so sánh độ dài của nó với 0 là hoàn toàn không hiệu quả nếu mảng có kích thước đáng kể. Ngoài ra, thông thường, bạn sẽ không phân bổ bộ nhớ cho một mảng trống (con trỏ vẫn không có giá trị), vì vậy sẽ không có ý nghĩa gì khi cố gắng lấy chiều dài của nó. Tôi không nói rằng len (a) == 0 không phải là một cách tốt để làm điều đó, nó chỉ không hét lên 'C' với tôi khi tôi nhìn thấy nó.
sleblanc

6
@BrennenSprimont, Nếu nó không kết thúc bằng null, thì bạn đã biết độ dài, cho dù nó được lưu trữ trong một biến riêng biệt hay mảng của bạn được bọc trong một số container theo dõi độ dài. C ++, Java, C # có các thùng chứa như vậy và thực hiện một số phương thức "độ dài" một cách hiệu quả. C không có điều đó , bạn phải tự lăn. Các mảng C được phân bổ tĩnh chỉ là các con trỏ tới một không gian bộ nhớ được đảm bảo có đủ dung lượng để lưu trữ lượng dữ liệu bạn yêu cầu. Không có gì được tích hợp vào C sẽ cho bạn biết bạn đã lấp đầy khoảng trống đó bao nhiêu.
sleblanc

1159

Cách thức pythonic để làm điều đó là từ hướng dẫn kiểu PEP 8 (trong đó nghĩa là khuyên dùng khuyên và Không có nghĩa là không được khuyến nghị).

Đối với các chuỗi, (chuỗi, danh sách, bộ dữ liệu), sử dụng thực tế là các chuỗi trống là sai.

Yes: if not seq:
     if seq:

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

49
Cách thứ hai có vẻ tốt hơn nếu bạn muốn báo hiệu seqđược dự kiến ​​là một loại đối tượng giống như danh sách.
BallpointBen

5
@BallpointBen mà, những người ủng hộ chủ nghĩa Python sẽ nói, nên được hiểu theo cách đặt tên của biến, càng nhiều càng tốt
axolotl

9
@BallpointBen thử sử dụng gợi ý loại của Python để báo hiệu biến số sẽ là gì. Nó được giới thiệu trong 3.5.
Boris

8
numpy đã phá vỡ thành ngữ này ... seq = numpy.array ([1,2,3]) theo sau nếu không seq sẽ đưa ra một ngoại lệ "ValueError: Giá trị thật của một mảng có nhiều hơn một phần tử là mơ hồ. Sử dụng a.any () hoặc a.all () "
Mr.WregMe 20/03/19

2
@jeronimo: Tôi tin rằng đó là một cảnh báo dành riêng cho lxml.
Harley Holcombe

767

Tôi thích nó một cách rõ ràng:

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

Bằng cách này, nó rõ ràng 100% lilà một chuỗi (danh sách) và chúng tôi muốn kiểm tra kích thước của nó. Vấn đề của tôi if not li: ...là nó mang lại ấn tượng sai đó lilà một biến boolean.


91
Kiểm tra xem độ dài của danh sách có bằng không, thay vì chỉ kiểm tra xem danh sách đó có sai hay không, có xấu và không đẹp. Bất cứ ai quen thuộc với Python sẽ không nghĩ lilà một bool, và sẽ không quan tâm. Nếu nó quan trọng, bạn nên thêm một bình luận, không thêm mã.
Carl Smith

21
Đây có vẻ như là một thử nghiệm chính xác không cần thiết, thường chậm hơn và IMHO luôn khó đọc hơn. Thay vì kiểm tra kích thước của một cái gì đó trống rỗng, tại sao không kiểm tra xem nó có trống không?
John B

34
Dù sao, lý do này là xấu (và rằng các thành ngữ vi phạm trong một ngôn ngữ có thành ngữ mạnh như Python nói chung là xấu) là vì nó báo hiệu cho người đọc rằng bạn đang kiểm tra cụ thể độ dài vì một số lý do (ví dụ: vì bạn muốn Nonehoặc 0để đưa ra một ngoại lệ chứ không phải thông qua). Vì vậy, khi bạn làm điều đó không có lý do, đó là gây hiểu lầm và nó cũng có nghĩa là khi mã của bạn không cần phải thực hiện sự phân biệt, sự khác biệt là vô hình vì bạn đã "khóc sói" trên tất cả các phần còn lại của nguồn.
abarnert

18
Tôi nghĩ rằng đây chỉ là việc kéo dài mã. Nếu không, tại sao không "rõ ràng" hơn với if bool(len(li) == 0) is True:?
5/2015

11
@Jabba sẽ là O (1) trong nhiều trường hợp (những nơi bạn làm việc với các loại dữ liệu tích hợp), nhưng bạn không thể dựa vào đó. Bạn có thể đang làm việc với một loại dữ liệu tùy chỉnh không có thuộc tính này. Bạn cũng có thể quyết định thêm loại dữ liệu tùy chỉnh này sau khi bạn đã viết mã này.
ralokt

324

Đây là lần truy cập đầu tiên của google cho "mảng trống kiểm tra python" và các truy vấn tương tự, cộng với những người khác dường như đang khái quát hóa câu hỏi ngoài danh sách, vì vậy tôi nghĩ rằng tôi đã thêm một cảnh báo cho một loại trình tự khác mà nhiều người có thể sử dụng.

Các phương thức khác không hoạt động cho mảng NumPy

Bạn cần cẩn thận với mảng NumPy, bởi vì các phương thức khác hoạt động tốt cho lists hoặc các thùng chứa tiêu chuẩn khác không thành công cho mảng NumPy. Tôi giải thích tại sao dưới đây, nhưng tóm lại, phương pháp ưa thích là sử dụng size.

Cách "pythonic" không hoạt động: Phần 1

Cách "pythonic" thất bại với mảng NumPy vì NumPy cố gắng truyền mảng thành một mảng bools và if xcố gắng đánh giá tất cả các bools đó cùng một lúc cho một loại giá trị chân lý tổng hợp nào đó. Nhưng điều này không có ý nghĩa gì, vì vậy bạn nhận được 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()

Cách "pythonic" không hoạt động: Phần 2

Nhưng ít nhất trường hợp trên cho bạn biết rằng nó đã thất bại. Nếu bạn tình cờ có một mảng NumPy với chính xác một phần tử, ifcâu lệnh sẽ "hoạt động", theo nghĩa là bạn không gặp lỗi. Tuy nhiên, nếu một yếu tố đó xảy ra là 0(hoặc 0.0, hoặc False, ...), ifcâu lệnh sẽ dẫn đến kết quả không chính xác False:

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

Nhưng rõ ràng xtồn tại và không trống rỗng! Kết quả này không phải là những gì bạn muốn.

Sử dụng lencó thể cho kết quả bất ngờ

Ví dụ,

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

trả về 1, mặc dù mảng có các phần tử bằng không.

Cách thức numpythonic

Như đã giải thích trong Câu hỏi thường gặp về SciPy , phương pháp đúng trong mọi trường hợp bạn biết bạn có mảng NumPy là sử dụng 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

Nếu bạn không chắc liệu đó có phải là listmột mảng NumPy hay thứ gì khác không, bạn có thể kết hợp phương pháp này với câu trả lời @dubiousjim đưa ra để đảm bảo kiểm tra đúng được sử dụng cho từng loại. Không phải là "pythonic", nhưng hóa ra NumPy đã cố tình phá vỡ pythonicity theo nghĩa này.

Nếu bạn cần làm nhiều hơn là chỉ kiểm tra xem đầu vào có trống không và bạn đang sử dụng các tính năng NumPy khác như lập chỉ mục hoặc hoạt động toán học, thì có lẽ hiệu quả hơn (và chắc chắn là phổ biến hơn) để buộc đầu vào một mảng NumPy. Có một vài chức năng tốt để thực hiện việc này một cách nhanh chóng - quan trọng nhất numpy.asarray. Cái này lấy đầu vào của bạn, không làm gì nếu nó đã là một mảng hoặc bọc đầu vào của bạn thành một mảng nếu nó là một danh sách, tuple, v.v., và tùy ý chuyển đổi nó thành lựa chọn của bạn dtype. Vì vậy, nó rất nhanh bất cứ khi nào có thể, và nó đảm bảo rằng bạn chỉ cần giả sử đầu vào là một mảng NumPy. Chúng tôi thậm chí thường chỉ sử dụng cùng một tên, vì việc chuyển đổi thành một mảng sẽ không khiến nó trở lại ngoài phạm vi hiện tại :

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

Điều này sẽ làm cho việc x.sizekiểm tra hoạt động trong tất cả các trường hợp tôi thấy trên trang này.


62
Điều đáng chú ý là đây không phải là một lỗ hổng trong Python, mà là sự phá vỡ hợp đồng có chủ ý bởi numpy- numpylà một thư viện với trường hợp sử dụng rất cụ thể và nó có một định nghĩa 'tự nhiên' khác về sự trung thực của một mảng đối với Tiêu chuẩn Python cho container. Thật hợp lý khi tối ưu hóa cho trường hợp đó, theo cách pathlibsử dụng /để nối các đường dẫn thay vì +- nó không chuẩn, nhưng có ý nghĩa trong ngữ cảnh.
Gareth Latty 16/2/2015

9
Đã đồng ý. Quan điểm của tôi chỉ là nó quan trọng cần nhớ NumPy rằng đã có những lựa chọn để phá vỡ gõ vịt cho cả rất phổ biến if xlen(x)thành ngữ - và đôi khi vỡ có thể rất khó để phát hiện và sửa lỗi.
Mike

22
Tôi không biết, đối với tôi, nếu một phương thức gọi là len (x) không trả về độ dài mảng vì các giả định, thì tên đó được thiết kế xấu.
Dalton

11
Câu hỏi này không liên quan gì đến mảng numpy
pppery

19
@ppperry Có, câu hỏi ban đầu không phải là về mảng Numpy, nhưng khi làm việc với những đối số và có thể là vịt gõ, câu hỏi này trở nên rất phù hợp.
peterhil

223

Cách tốt nhất để kiểm tra nếu một danh sách trống

Ví dụ: nếu được thông qua như sau:

a = []

Làm thế nào để tôi kiểm tra xem a có trống không?

Câu trả lời ngắn:

Đặt danh sách trong ngữ cảnh boolean (ví dụ: bằng một câu lệnh ifhoặc while). Nó sẽ kiểm tra Falsenếu nó trống, và Truenếu không. Ví dụ:

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

PEP 8

PEP 8 , hướng dẫn kiểu Python chính thức cho mã Python trong thư viện chuẩn của Python, khẳng định:

Đối với các chuỗi, (chuỗi, danh sách, bộ dữ liệu), sử dụng thực tế là các chuỗi trống là sai.

Yes: if not seq:
     if seq:

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

Chúng ta nên kỳ vọng rằng mã thư viện chuẩn phải có hiệu suất và chính xác nhất có thể. Nhưng tại sao lại như vậy, và tại sao chúng ta cần hướng dẫn này?

Giải trình

Tôi thường thấy mã như thế này từ các lập trình viên có kinh nghiệm mới biết về Python:

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

Và người dùng ngôn ngữ lười biếng có thể bị cám dỗ để làm điều này:

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

Đây là chính xác trong các ngôn ngữ khác tương ứng của họ. Và điều này thậm chí còn đúng về mặt ngữ nghĩa trong Python.

Nhưng chúng tôi coi đó là un-Pythonic vì Python hỗ trợ các ngữ nghĩa này trực tiếp trong giao diện của đối tượng danh sách thông qua cưỡng chế boolean.

Từ các tài liệu (và lưu ý cụ thể là bao gồm danh sách trống, []):

Theo mặc định, một đối tượng được coi là đúng trừ khi lớp của nó định nghĩa một __bool__()phương thức trả về Falsehoặc một __len__()phương thức trả về 0, khi được gọi với đối tượng. Dưới đây là hầu hết các đối tượng tích hợp được coi là sai:

  • hằng được định nghĩa là sai: NoneFalse.
  • zero của bất kỳ loại số: 0, 0.0, 0j, Decimal(0),Fraction(0, 1)
  • chuỗi rỗng và bộ sưu tập: '', (), [], {}, set(),range(0)

Và tài liệu datamodel:

object.__bool__(self)

Được gọi để thực hiện kiểm tra giá trị thật và hoạt động tích hợp bool(); nên trả lại Falsehoặc True. Khi phương thức này không được xác định, __len__()được gọi, nếu nó được xác định và đối tượng được coi là đúng nếu kết quả của nó là khác không. Nếu một lớp định nghĩa không phải __len__() cũng không __bool__(), tất cả các thể hiện của nó được coi là đúng.

object.__len__(self)

Được gọi để thực hiện chức năng tích hợp len(). Nên trả về độ dài của đối tượng, một số nguyên> = 0. Ngoài ra, một đối tượng không xác định __bool__()phương thức và __len__()phương thức trả về 0 được coi là sai trong ngữ cảnh Boolean.

Vì vậy, thay vì điều này:

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

hoặc này:

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

Làm cái này:

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

Làm những gì Pythonic thường mang lại hiệu quả:

Nó có trả hết không? (Lưu ý rằng ít thời gian hơn để thực hiện một thao tác tương đương sẽ tốt hơn :)

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

Đối với tỷ lệ, đây là chi phí gọi hàm và xây dựng và trả về một danh sách trống, mà bạn có thể trừ vào chi phí của kiểm tra trống rỗng được sử dụng ở trên:

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

Chúng ta thấy rằng một trong hai kiểm tra cho chiều dài với các chức năng được xây dựng trong lenso với 0 hoặc kiểm tra đối với một danh sách rỗng là nhiều ít performant hơn bằng cách sử dụng cú pháp dựng sẵn của ngôn ngữ như tài liệu.

Tại sao?

Đối với len(a) == 0kiểm tra:

Python đầu tiên phải kiểm tra toàn cầu để xem lencó bị bóng không.

Sau đó, nó phải gọi hàm, tải 0và thực hiện so sánh đẳng thức trong Python (thay vì với C):

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

Và đối với [] == []nó, nó phải xây dựng một danh sách không cần thiết và sau đó, một lần nữa, thực hiện thao tác so sánh trong máy ảo của Python (trái ngược với C)

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

Cách "Pythonic" là một kiểm tra đơn giản và nhanh hơn nhiều vì độ dài của danh sách được lưu trong bộ đệm của đối tượng:

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

Bằng chứng từ nguồn C và tài liệu

PyVarObject

Đây là một phần mở rộng của trường PyObjectthêm ob_size. Điều này chỉ được sử dụng cho các đối tượng có một số khái niệm về chiều dài. Loại này không thường xuất hiện trong API Python / C. Nó tương ứng với các trường được xác định bởi sự mở rộng của PyObject_VAR_HEADmacro.

Từ nguồn c trong Bao gồm / listobject.h :

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

Phản hồi ý kiến:

Tôi sẽ chỉ ra rằng điều này cũng đúng cho không trống trường hợp mặc dù khá xấu xí của nó như với l=[]sau đó %timeit len(l) != 090,6 ns ± 8,3 ns, %timeit l != []55,6 ns ± 3,09, %timeit not not l38,5 ns ± 0,372. Nhưng không có cách nào bất cứ ai sẽ tận hưởng not not lmặc dù tốc độ gấp ba. Trông thật lố bịch. Nhưng tốc độ chiến thắng
tôi cho rằng vấn đề đang thử nghiệm với thời gian vì vừa if l:đủ nhưng đáng ngạc nhiên %timeit bool(l)mang lại 101 ns ± 2,64 ns. Thú vị là không có cách nào để ép buộc bool mà không bị phạt này. %timeit llà vô ích vì không có chuyển đổi sẽ xảy ra.

Phép thuật IPython, %timeitkhông hoàn toàn vô dụng ở đây:

In [1]: l = []                                                                  

In [2]: %timeit l                                                               
20 ns ± 0.155 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)

In [3]: %timeit not l                                                           
24.4 ns ± 1.58 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [4]: %timeit not not l                                                       
30.1 ns ± 2.16 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

Chúng ta có thể thấy có một chút chi phí tuyến tính cho mỗi bổ sung notở đây. Chúng tôi muốn xem chi phí, ceteris paribus , nghĩa là, tất cả những thứ khác đều bằng nhau - nơi tất cả những thứ khác được giảm thiểu đến mức có thể:

In [5]: %timeit if l: pass                                                      
22.6 ns ± 0.963 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [6]: %timeit if not l: pass                                                  
24.4 ns ± 0.796 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [7]: %timeit if not not l: pass                                              
23.4 ns ± 0.793 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

Bây giờ hãy xem xét trường hợp cho một danh sách thất nghiệp:

In [8]: l = [1]                                                                 

In [9]: %timeit if l: pass                                                      
23.7 ns ± 1.06 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [10]: %timeit if not l: pass                                                 
23.6 ns ± 1.64 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [11]: %timeit if not not l: pass                                             
26.3 ns ± 1 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

Những gì chúng ta có thể thấy ở đây là nó tạo ra một chút khác biệt cho dù bạn chuyển thực tế boolvào kiểm tra điều kiện hay chính danh sách, và nếu có bất cứ điều gì, đưa ra danh sách, như là, sẽ nhanh hơn.

Python được viết bằng C; nó sử dụng logic của nó ở cấp độ C. Bất cứ điều gì bạn viết bằng Python sẽ chậm hơn. Và nó có thể sẽ là các đơn đặt hàng có cường độ chậm hơn trừ khi bạn sử dụng các cơ chế được tích hợp trực tiếp vào Python.


Tôi sẽ chỉ ra rằng điều này cũng đúng cho không trống trường hợp mặc dù khá xấu xí của nó như với l=[]sau đó %timeit len(l) != 090,6 ns ± 8,3 ns, %timeit l != []55,6 ns ± 3,09, %timeit not not l38,5 ns ± 0,372. Nhưng không có cách nào bất cứ ai sẽ tận hưởng not not lmặc dù tốc độ gấp ba. Trông thật lố bịch. Nhưng tốc độ chiến thắng
Gregory Morse

Tôi cho rằng vấn đề đang thử nghiệm với thời gian vì chỉ if l:là đủ nhưng đáng ngạc nhiên %timeit bool(l)mang lại 101 ns ± 2,64 ns. Thú vị là không có cách nào để ép buộc bool mà không bị phạt này. %timeit llà vô ích vì không có chuyển đổi sẽ xảy ra.
Gregory Morse

138

Một danh sách trống tự nó được coi là sai trong kiểm tra giá trị thực (xem tài liệu python ):

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

@ Thomas Thomas

EDIT: Một điểm khác chống lại việc kiểm tra danh sách trống là Sai: Thế còn đa hình? Bạn không nên phụ thuộc vào một danh sách là một danh sách. Nó chỉ nên quẫy như một con vịt - làm thế nào bạn có thể đưa chú vịt của mình đi lang thang '' Sai '' khi nó không có yếu tố nào?

DuckCollection của bạn nên thực hiện __nonzero__hoặc __len__vì vậy nếu a: sẽ hoạt động mà không gặp vấn đề gì.


Lạ thay cách [] == Falseđánh giá thành Sai mặc dù
information_interchange

@in information_interchange Nếu bạn muốn kiểm tra rõ ràng tính trung thực của một giá trị, hãy sử dụng bool(). bool([]) == Falsesẽ đánh giá Truenhư mong đợi.
tám

103

Câu trả lời (được chấp nhận) của Patrick là đúng: if not a:là cách đúng để làm điều đó. Câu trả lời của Harley Holcombe là đúng rằng đây là trong hướng dẫn phong cách PEP 8. Nhưng điều mà không câu trả lời nào giải thích được là tại sao nên theo dõi thành ngữ này ngay cả khi cá nhân bạn thấy nó không đủ rõ ràng hoặc gây nhầm lẫn cho người dùng Ruby hoặc bất cứ điều gì.

Mã Python và cộng đồng Python có thành ngữ rất mạnh. Theo các thành ngữ này làm cho mã của bạn dễ đọc hơn đối với bất kỳ ai có kinh nghiệm về Python. Và khi bạn vi phạm những thành ngữ đó, đó là một tín hiệu mạnh mẽ.

Đúng là if not a:không phân biệt danh sách trống với None, hoặc số 0 hoặc bộ dữ liệu trống hoặc loại bộ sưu tập do người dùng tạo trống hoặc loại bộ sưu tập không hoàn toàn do người dùng tạo hoặc mảng NumPy một phần tử đóng vai trò vô hướng với falsey giá trị, vv Và đôi khi điều quan trọng là phải rõ ràng về điều đó. Và trong trường hợp đó, bạn biết những gì bạn muốn được về rõ ràng, vì vậy bạn có thể kiểm tra cho chính xác điều đó. Ví dụ: if not a and a is not None:có nghĩa là "bất cứ điều gì chim ưng trừ Không có", trong khi đó if len(a) != 0:có nghĩa là "chỉ các chuỗi trống rỗng và bất cứ điều gì ngoài một chuỗi là một lỗi ở đây", v.v. Bên cạnh việc kiểm tra chính xác những gì bạn muốn kiểm tra, điều này cũng báo hiệu cho người đọc rằng thử nghiệm này rất quan trọng.

Nhưng khi bạn không có bất cứ điều gì để nói rõ ràng, bất cứ điều gì khác hơn if not a:là gây hiểu lầm cho người đọc. Bạn đang báo hiệu điều gì đó quan trọng khi nó không. (Bạn cũng có thể làm cho mã ít linh hoạt, hoặc chậm hơn, hoặc bất cứ điều gì, nhưng đó là tất cả ít quan trọng.) Và nếu bạn có thói quen đánh lừa người đọc như thế này, sau đó khi bạn làm cần phải thực hiện một sự phân biệt, nó sẽ vượt qua vì không được chú ý bạn đã "khóc sói" trên tất cả các mã của bạn.


78

Tại sao phải kiểm tra cả?

Không ai dường như đã giải quyết vấn của bạn cần để kiểm tra danh sách ở nơi đầu tiên. Vì bạn không cung cấp thêm ngữ cảnh, tôi có thể tưởng tượng rằng bạn có thể không cần thực hiện kiểm tra này ngay từ đầu, nhưng không quen với việc xử lý danh sách trong Python.

Tôi sẽ lập luận rằng cách thức pythonic nhất là không kiểm tra tất cả, mà là chỉ xử lý danh sách. Bằng cách đó, nó sẽ làm điều đúng dù trống hay đầy.

a = []

for item in a:
    <do something with item>

<rest of code>

Điều này có lợi ích của việc xử lý bất kỳ nội dung nào của a , trong khi không yêu cầu kiểm tra cụ thể về sự trống rỗng. Nếu a trống, khối phụ thuộc sẽ không thực thi và trình thông dịch sẽ chuyển sang dòng tiếp theo.

Nếu bạn thực sự cần kiểm tra mảng cho sự trống rỗng, các câu trả lời khác là đủ.


3
Vấn đề là, kiểm tra xem danh sách trống có khá quan trọng không, ít nhất là đối với tôi. Bạn đã xem xét nếu có một số tập lệnh bên trong <rest of code>có thể sử dụng kết quả từ forvòng lặp? Hoặc trực tiếp sử dụng một số giá trị trong a? Thật vậy, nếu tập lệnh được thiết kế để chạy với đầu vào được kiểm soát chặt chẽ, việc kiểm tra có thể hơi không cần thiết. Nhưng trong hầu hết các trường hợp, đầu vào khác nhau, và kiểm tra thường tốt hơn.
Amarth Gûl

Trân trọng, không. Điều tôi đã xem xét là một người không biết đủ về Python để biết rằng, nếu <list>: thì đó là câu trả lời đúng, hỏi làm thế nào để kiểm tra danh sách trống. Sau đó, tôi nhận thấy rất nhiều câu trả lời đưa ra các ý kiến ​​khác nhau, nhưng dường như không có câu trả lời nào cho nhu cầu ban đầu. Đó là những gì tôi đã cố gắng thực hiện với câu trả lời của mình để họ kiểm tra nhu cầu trước khi tiếp tục. Tôi tin rằng tôi đã đề nghị nhiều như vậy trong câu trả lời của tôi, rõ ràng.
MrWonderful 17/2/18

@ AmarthGûl - Làm thế nào một người có thể nhận được kết quả từ vòng lặp for đến tập lệnh bên trong <phần còn lại của mã> để được xử lý? Trong một danh sách, có lẽ? Hoặc có thể là một dict? Nếu vậy, logic tương tự được áp dụng. Tôi không hiểu làm thế nào đầu vào biến có thể có bất kỳ ảnh hưởng nào trong bất kỳ loại mã được thiết kế hợp lý nào, trong đó việc xử lý một danh sách trống sẽ là một ý tưởng tồi.
MrWonderful

Một chút cũ nhưng nếu bạn chỉ kiểm tra xem danh sách có trống không, đối với một danh sách không trống, mã của bạn sẽ lặp đi lặp lại quá trình khi OP chỉ đơn giản là tìm kiếm một hoạt động kiểm tra. Chỉ cần tưởng tượng một trường hợp tồi tệ hơn cho mã đó khi n tiến đến vô cùng ....
DJK

7
@DJK - Không, tôi nghĩ bạn vẫn còn thiếu nó. Có lẽ bạn muốn làm một cái gì đó với một danh sách, nếu bạn có một danh sách. Bạn sẽ làm gì khác nếu nó trống? Trở về sớm? Nếu nó không trống thì sao? xử lý nó? Vấn đề là, có lẽ bạn không cần phải kiểm tra danh sách trống, chỉ cần lặp lại nó và làm bất cứ điều gì bạn sẽ làm với các yếu tố. Nếu không có yếu tố, bạn rơi qua. Nếu có các yếu tố, bạn xử lý chúng khi bạn cần. Vấn đề là KHÔNG sử dụng ví dụ CHO một kiểm tra trống mà là KHÔNG kiểm tra tất cả, chỉ xử lý danh sách.
MrWonderful


40

Tôi đã viết:

if isinstance(a, (list, some, other, types, i, accept)) and not a:
    do_stuff

được bình chọn -1. Tôi không chắc đó có phải là do độc giả phản đối chiến lược hay nghĩ rằng câu trả lời không hữu ích như đã trình bày. Tôi sẽ giả vờ đó là cái thứ hai, vì --- bất cứ thứ gì được tính là "pythonic" --- đây là chiến lược chính xác. Trừ khi bạn đã loại trừ hoặc sẵn sàng xử lý các trường hợp a, ví dụ False, bạn cần một bài kiểm tra hạn chế hơn chỉ if not a:. Bạn có thể sử dụng một cái gì đó như thế này:

if isinstance(a, numpy.ndarray) and not a.size:
    do_stuff
elif isinstance(a, collections.Sized) and not a:
    do_stuff

bài kiểm tra đầu tiên là để đáp lại câu trả lời của @ Mike, ở trên. Dòng thứ ba cũng có thể được thay thế bằng:

elif isinstance(a, (list, tuple)) and not a:

nếu bạn chỉ muốn chấp nhận các thể hiện của các loại cụ thể (và các kiểu con của chúng) hoặc với:

elif isinstance(a, (list, tuple)) and not len(a):

Bạn có thể thoát khỏi mà không cần kiểm tra loại rõ ràng, nhưng chỉ khi bối cảnh xung quanh đã đảm bảo với bạn rằng đó alà giá trị của các loại bạn chuẩn bị xử lý hoặc nếu bạn chắc chắn rằng các loại bạn chưa chuẩn bị xử lý sẽ xảy ra để phát sinh lỗi (ví dụ: TypeErrornếu bạn gọi lenmột giá trị không xác định) mà bạn chuẩn bị xử lý. Nhìn chung, các công ước "pythonic" dường như đi theo con đường cuối cùng này. Bóp nó như một con vịt và để nó nuôi DuckError nếu nó không biết cách quẫy. Tuy nhiên, bạn vẫn phải suy nghĩ về loại giả định nào bạn đang thực hiện và liệu các trường hợp bạn chưa chuẩn bị để xử lý đúng có thực sự sẽ xảy ra lỗi ở đúng nơi hay không. Mảng Numpy là một ví dụ điển hình khi chỉ dựa vào một cách mù quánglen hoặc typecast boolean có thể không làm chính xác những gì bạn mong đợi.


3
Thật hiếm khi bạn có một danh sách đầy đủ gồm 6 loại mà bạn muốn chấp nhận và không linh hoạt cho bất kỳ loại nào khác. Khi bạn cần loại điều đó, bạn có thể muốn có một ABC. Trong trường hợp này, nó có thể là một trong những ABC stdlib, thích collections.abc.Sizedhoặc collections.abc.Sequence, nhưng nó có thể là một trong những bạn tự viết và viết register(list). Nếu bạn thực sự có mã trong đó rất quan trọng để phân biệt trống với các falsey khác và cũng để phân biệt các danh sách và bộ dữ liệu với bất kỳ chuỗi nào khác, thì đây là chính xác nhưng tôi không tin rằng bạn có mã như vậy.
abarnert

13
Lý do mọi người không thích điều này là vì nó hoàn toàn không phù hợp trong hầu hết các trường hợp. Python là một ngôn ngữ gõ vịt, và mức độ mã hóa phòng thủ này chủ động cản trở điều đó. Ý tưởng đằng sau hệ thống loại của Python là mọi thứ sẽ hoạt động miễn là đối tượng truyền vào các hàm theo cách nó cần. Bằng cách thực hiện kiểm tra loại rõ ràng, bạn đang buộc người gọi sử dụng các loại cụ thể, đi ngược lại chính ngôn ngữ. Mặc dù đôi khi những thứ như vậy là cần thiết (không bao gồm các chuỗi được coi là chuỗi), những trường hợp như vậy rất hiếm và hầu như luôn luôn tốt nhất dưới dạng danh sách đen.
Gareth Latty 16/2/2015

1
Nếu bạn thực sự muốn kiểm tra xem giá trị đó có chính xác []không và không phải là thứ gì đó sai lệch của loại khác, thì chắc chắn if a == []:là được yêu cầu, thay vì mucking về isinstance.
RemcoGerlich 16/07/2015

2
Có một số ép buộc tự động ==mặc dù. Ngoài đỉnh đầu, tôi không thể xác định bất kỳ cho []. [] == ()ví dụ trả về False. Nhưng ví dụ frozenset()==set()trả về True. Vì vậy, ít nhất nên đưa ra một số suy nghĩ về việc liệu một số loại không mong muốn có thể bị ép buộc [](hoặc ngược lại) khi thực hiện a == [].
dubiousjim 16/07/2015

@RemcoGerlich - isinstance () vẫn thích hợp hơn là xây dựng một danh sách trống để so sánh với. Ngoài ra, như một cách khác đã chỉ ra, toán tử đẳng thức có thể gọi chuyển đổi ngầm định của một số loại, điều này có thể không mong muốn. Không có lý do gì để mã "a == []" và mã đó chắc chắn sẽ bị gắn cờ là một khiếm khuyết trong bất kỳ đánh giá mã nào tôi đã tham gia. Sử dụng công cụ thích hợp được cung cấp bởi ngôn ngữ không nên được coi là "mucking về , "nhưng đúng hơn là" kỹ thuật lập trình tốt. "
MrWonderful

29

Từ tài liệu về kiểm tra giá trị thật:

Tất cả các giá trị khác với những gì được liệt kê ở đây được xem xét True

  • None
  • False
  • zero của bất kỳ loại số, ví dụ, 0, 0.0, 0j.
  • bất kỳ chuỗi rỗng, ví dụ, '', (), [].
  • bất kỳ ánh xạ trống, ví dụ , {}.
  • các thể hiện của các lớp do người dùng định nghĩa, nếu lớp định nghĩa a __bool__()hoặc __len__()phương thức, khi phương thức đó trả về giá trị 0 hoặc giá trị bool False.

Có thể thấy, danh sách trống []là giả mạo , do đó, làm những gì sẽ được thực hiện với giá trị boolean nghe có vẻ hiệu quả nhất:

if not a:
    print('"a" is empty!')

@DJ_Stuffy_K khẳng định những gì trong thử nghiệm đơn vị, một danh sách trống? Chỉ cần sử dụng assert(not myList). Nếu bạn cũng muốn khẳng định đối tượng là a list, bạn có thể sử dụng assertIsInstance().
Sнаđошƒаӽ

24

Dưới đây là một số cách bạn có thể kiểm tra xem danh sách có trống không:

a = [] #the list

1) Cách pythonic khá đơn giản:

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

Trong Python, các thùng chứa trống như danh sách, bộ dữ liệu, bộ, ký tự, biến vv được xem như False. Người ta có thể chỉ cần coi danh sách là một vị ngữ ( trả về giá trị Boolean ). Và một Truegiá trị sẽ chỉ ra rằng nó không trống.

2) Một cách rõ ràng: sử dụng len()để tìm độ dài và kiểm tra xem nó có bằng 0:

if len(a) == 0:
    print("a is empty")

3) Hoặc so sánh nó với một danh sách trống ẩn danh:

if a == []:
    print("a is empty")

4) Một cách khác để làm là ngớ ngẩn là sử dụng exceptioniter():

try:
    next(iter(a))
    # list has elements
except StopIteration:
    print("Error: a is empty")

20

Tôi thích những điều sau đây:

if a == []:
   print "The list is empty."

37
Điều này sẽ chậm hơn, khi bạn khởi tạo một danh sách trống thêm không cần thiết.
Carl Meyer

32
Điều này ít đọc hơn if not a:và dễ dàng phá vỡ hơn. Xin đừng làm điều đó.
devsnd

Có một điểm tốt được thực hiện trước đó () == []cũng bằng sai. Mặc dù tôi thích cách triển khai này đọc if not a:tất cả các trường hợp, nhưng nếu bạn chắc chắn đang mong đợi một danh sách thì ví dụ của bạn là đủ.
Một ngôi sao

19

Phương pháp 1 (Ưu tiên):

if not a : 
   print ("Empty") 

Cách 2:

if len(a) == 0 :
   print( "Empty" )

Cách 3:

if a == [] :
  print ("Empty")

12
def list_test (L):
    if   L is None  : print('list is None')
    elif not L      : print('list is empty')
    else: print('list has %d elements' % len(L))

list_test(None)
list_test([])
list_test([1,2,3])

Đôi khi tốt để kiểm tra Nonevà cho sự trống rỗng một cách riêng biệt vì đó là hai trạng thái khác nhau. Đoạn mã trên tạo ra đầu ra sau:

list is None 
list is empty 
list has 3 elements

Mặc dù nó không có giá trị gì Nonelà giả. Vì vậy, nếu bạn không muốn tách riêng thử nghiệm cho None-ness, bạn không phải làm điều đó.

def list_test2 (L):
    if not L      : print('list is empty')
    else: print('list has %d elements' % len(L))

list_test2(None)
list_test2([])
list_test2([1,2,3])

sản xuất dự kiến

list is empty
list is empty
list has 3 elements

8

Nhiều câu trả lời đã được đưa ra, và rất nhiều trong số đó là khá tốt. Tôi chỉ muốn thêm rằng kiểm tra

not a

cũng sẽ vượt qua Nonevà các loại cấu trúc trống khác. Nếu bạn thực sự muốn kiểm tra danh sách trống, bạn có thể làm điều này:

if isinstance(a, list) and len(a)==0:
    print("Received an empty list")

Có thể điều này đưa ra một ngoại lệ, nếu akhông phải là một danh sách và akhông có phương thức nào được __len__thực hiện. Tôi muốn giới thiệu:if isinstance(obj, list): if len(obj) == 0: print '...'
Sven Krüger

4
@ SvenKrüger không. Toán tử andlà lười biếng trong Python. Không có gì sau đó andsẽ được thực thi nếu điều kiện trước andlà Sai.
ElmoVanKielmo

7

chúng ta có thể sử dụng một cách đơn giản nếu khác:

item_list=[]
if len(item_list) == 0:
    print("list is empty")
else:
    print("list is not empty")

5
-1 - Để tránh nhầm lẫn, đừng sử dụng một từ dành riêng cho tên biến hoặc bạn có thể có hành vi đáng ngạc nhiên vào lần tới khi bạn cố gắng gọi, ví dụ như "list ()" ... một cái gì đó như đối tượng "TypeError: 'list' là không thể gọi được "hoặc một số như vậy.
MrWonderful

6

Nếu bạn muốn kiểm tra xem danh sách có trống không:

l = []
if l:
    # do your stuff.

Nếu bạn muốn kiểm tra xem tất cả các giá trị trong danh sách có trống không. Tuy nhiên, nó sẽ Truedành cho một danh sách trống:

l = ["", False, 0, '', [], {}, ()]
if all(bool(x) for x in l):
    # do your stuff.

Nếu bạn muốn sử dụng cả hai trường hợp với nhau:

def empty_list(lst):
    if len(lst) == 0:
        return False
    else:
        return all(bool(x) for x in l)

Bây giờ bạn có thể sử dụng:

if empty_list(lst):
    # do your stuff.

1
tất cả (bool (x) cho x in l) là Đúng cho danh sách trống
gberger

5

Lấy cảm hứng từ giải pháp của @ dubiousjim, tôi đề xuất sử dụng một kiểm tra tổng quát bổ sung xem nó có phải là thứ gì đó có thể lặp lại được không

import collections
def is_empty(a):
    return not a and isinstance(a, collections.Iterable)

Lưu ý: một chuỗi được coi là có thể lặp lại. - thêm and not isinstance(a,(str,unicode))nếu bạn muốn loại trừ chuỗi trống

Kiểm tra:

>>> is_empty('sss')
False
>>> is_empty(555)
False
>>> is_empty(0)
False
>>> is_empty('')
True
>>> is_empty([3])
False
>>> is_empty([])
True
>>> is_empty({})
True
>>> is_empty(())
True

1
Đường cao tốc; đây chỉ là hỏi xem một danh sách có trống không, có phải là một cái gì đó có thể lặp lại không.
pppery

1
Nếu tôi không hài lòng if a:, đó là vì tôi muốn có một ngoại lệ nếu akhông phải là một loại container. (Là một iterable cũng cho phép lặp, có thể không hữu ích được thử nghiệm cho sự trống rỗng.)
Davis Herring

5
print('not empty' if a else 'empty')

thực tế hơn một chút:

a.pop() if a else None

và phiên bản shertest:

if a: a.pop() 

4

Từ python3 trở đi bạn có thể sử dụng

a == []

để kiểm tra xem danh sách có trống không

EDIT: Điều này cũng hoạt động với python2.7 ..

Tôi không chắc tại sao có quá nhiều câu trả lời phức tạp. Nó khá rõ ràng và đơn giản


1
vui lòng giải thích thêm về cách thức hoạt động mà không cần viết "nếu"?
ganeshdeshmukh

3
Đây không phải là pythonic cũng không phải là một ví dụ hoàn chỉnh. Ngoài ra, nó khởi tạo một danh sách trống mỗi khi nó gặp phải. Đừng làm điều này.
MrWonderful

@MrWonderful nó không khởi tạo một danh sách trống mỗi lần. Nó chỉ xác minh nếu danh sách hiện có atrống hay không.
Tessaracter

@MrWonderful Tôi không hiểu cái gì tạo ra nópythonic
Tessaracter

@ganeshdeshmukh nếu bạn sử dụng a==[]nó sẽ in đúng trên thiết bị đầu cuối python nếu a trống. Khác nó sẽ in sai. Bạn có thể sử dụng điều này trong một điều kiện nếu nhưif(a==[])
Tessaracter

3

Bạn thậm chí có thể thử sử dụng bool () như thế này

    a = [1,2,3];
    print bool(a); # it will return True
    a = [];
    print bool(a); # it will return False

Tôi thích cách này để kiểm tra danh sách có trống hay không.

Rất tiện dụng và hữu ích.


4
Đối với những người (như tôi), những người không biết, bool()chuyển đổi biến Python thành boolean để bạn có thể lưu trữ tính trung thực hoặc giả của giá trị mà không phải sử dụng câu lệnh if. Tôi nghĩ rằng nó ít dễ đọc hơn chỉ đơn giản là sử dụng một câu trả lời có điều kiện như câu trả lời được chấp nhận, nhưng tôi chắc chắn có những trường hợp sử dụng tốt khác cho nó.
Galen Long

Điều này có thể sử dụng trong một biểu thức và ngắn gọn hơn.
qneill

3

Chỉ cần sử dụng is_empty () hoặc tạo hàm như: -

def is_empty(any_structure):
    if any_structure:
        print('Structure is not empty.')
        return True
    else:
        print('Structure is empty.')
        return False  

Nó có thể được sử dụng cho bất kỳ dữ liệu cấu trúc nào như danh sách, bộ dữ liệu, từ điển và nhiều hơn nữa. Bằng cách này, bạn có thể gọi nó nhiều lần bằng cách sử dụng is_empty(any_structure).


3
Cái tên is_emptycho thấy nó trả về một cái gì đó. Nhưng nếu có, một thứ gì đó sẽ trở thành bool(any_structure), mà bạn nên sử dụng thay thế ( khi bạn cần một thứ boolgì đó).
Davis Herring

4
Tại sao chúng ta muốn một biến thể trên boolđó (cũng) in các thông điệp thành đầu ra tiêu chuẩn?
Davis Herring

@DavisHerring Chúng tôi luôn có hai lựa chọn đầu tiên là in bằng chức năng khác là sử dụng boolbiến trả về . Sự lựa chọn là của bạn. Tôi viết cả hai để bạn có thể chọn giữa chúng.
Vine Jain

3

Cách đơn giản là kiểm tra độ dài bằng không.

if len(a) == 0:
    print("a is empty")

1

Giá trị thật của một danh sách trống là Falsetrong khi đó đối với một danh sách không trống True.


1

Điều đưa tôi đến đây là một trường hợp sử dụng đặc biệt: Tôi thực sự muốn một chức năng cho tôi biết nếu một danh sách trống hay không. Tôi muốn tránh viết chức năng của riêng tôi hoặc sử dụng biểu thức lambda ở đây (vì có vẻ như nó đủ đơn giản):

foo = itertools.takewhile(is_not_empty, (f(x) for x in itertools.count(1)))

Và, tất nhiên, có một cách rất tự nhiên để làm điều đó:

foo = itertools.takewhile(bool, (f(x) for x in itertools.count(1)))

Tất nhiên, không sử dụng booltrong if(nghĩa là if bool(L):) bởi vì nó ngụ ý. Nhưng, đối với các trường hợp khi "không trống" rõ ràng là cần thiết như một hàm, boollà lựa chọn tốt nhất.


1

Để kiểm tra xem danh sách có trống hay không, bạn có thể sử dụng hai cách sau. Nhưng hãy nhớ rằng, chúng ta nên tránh cách kiểm tra rõ ràng một loại trình tự (đó là một less pythoniccách):

def enquiry(list1): 
    if len(list1) == 0: 
        return 0
    else: 
        return 1

# ––––––––––––––––––––––––––––––––

list1 = [] 

if enquiry(list1): 
    print ("The list isn't empty") 
else: 
    print("The list is Empty") 

# Result: "The list is Empty".

Cách thứ hai là một more pythonic. Phương pháp này là một cách kiểm tra ngầm và thích hợp hơn nhiều so với phương pháp trước.

def enquiry(list1): 
    if not list1: 
        return True
    else: 
        return False

# ––––––––––––––––––––––––––––––––

list1 = [] 

if enquiry(list1): 
    print ("The list is Empty") 
else: 
    print ("The list isn't empty") 

# Result: "The list is Empty"

Hi vọng điêu nay co ich.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.