如何检查列表是否为空?
- 2024-11-29 08:41:00
- admin 原创
- 162
问题描述:
例如,如果传递了以下内容:
a = []
我如何检查是否a
为空?
解决方案 1:
if not a:
print("List is empty")
使用空的隐式布尔值list
非常符合 Pythonic。
解决方案 2:
实现此目的的 Python 方式源自PEP 8 风格指南。
对于序列(字符串、列表、元组),使用空序列为假的事实:
# Correct: if not seq: if seq: # Wrong: if len(seq): if not len(seq):
解决方案 3:
我更喜欢这样:
if len(li) == 0:
print('the list is empty')
这样就 100% 清楚了这li
是一个序列(列表),我们想测试它的大小。我的问题if not li: ...
是它给人一种错误的印象,即它li
是一个布尔变量。
解决方案 4:
这是谷歌首次搜索到“python 测试空数组”及其类似的查询,其他人正在将这个问题推广到列表之外,因此这里对很多人使用的不同类型的序列提出警告。
其他方法不适用于 NumPy 数组
您需要谨慎使用 NumPy 数组,因为其他适用于list
s 或其他标准容器的方法对 NumPy 数组不起作用。我在下面解释了原因,但简而言之,首选方法是使用size
。
“pythonic” 方式行不通:第一部分
“pythonic” 方法无法处理 NumPy 数组,因为 NumPy 会尝试将数组转换为 s 数组bool
,并if x
尝试一次性评估所有这些bool
s 以获得某种聚合真值。但这没有任何意义,因此您会得到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” 方式行不通:第 2 部分
但至少上面的情况告诉你它失败了。如果你碰巧有一个只有一个元素的 NumPy 数组,那么该if
语句将“起作用”,也就是说你不会收到错误。但是,如果那个元素恰好是0
(或0.0
,或False
,...),该if
语句将错误地导致False
:
>>> x = numpy.array([0,])
>>> if x: print("x")
... else: print("No x")
No x
但明明x
存在,且不为空!这个结果不是你想要的。
使用len
可能会产生意想不到的结果
例如,
len( numpy.zeros((1,0)) )
返回 1,即使数组没有元素。
numpythonic 方式
正如SciPy FAQ中所述,在您知道自己有一个 NumPy 数组的所有情况下,正确的方法是使用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
如果您不确定它可能是list
、NumPy 数组还是其他东西,您可以将此方法与@dubiousjim 给出的答案结合起来,以确保对每种类型使用正确的测试。不是很“pythonic”,但事实证明 NumPy 至少在这个意义上故意破坏了 pythonicity。
如果您需要做的不仅仅是检查输入是否为空,而且还在使用其他 NumPy 功能(如索引或数学运算),那么强制输入为NumPy 数组可能更有效(当然也更常见)。有几个不错的函数可以快速完成此操作 - 最重要的是numpy.asarray
。这会接受您的输入,如果它已经是一个数组,则不执行任何操作,或者如果它是列表、元组等,则将您的输入包装到数组中,并可选择将其转换为您选择的dtype
。所以只要可能,它就会非常快,并且可以确保您假设输入是一个 NumPy 数组。我们通常甚至只使用相同的名称,因为转换为数组不会使其回到当前范围之外:
x = numpy.asarray(x, dtype=numpy.double)
这将使x.size
检查在本页面我看到的所有情况下都能正常工作。
解决方案 5:
检查列表是否为空的最佳方法
例如,如果传递了以下内容:
a = []
我如何检查 a 是否为空?
简短回答:
将列表放在布尔上下文中(例如,使用if
或while
语句)。它将测试False
它是否为空,True
否则为空。例如:
if not a: # do this!
print('a is an empty list')
PEP 8
PEP 8是 Python 标准库中 Python 代码的官方 Python 风格指南,它断言:
对于序列(字符串、列表、元组),使用空序列为假的事实。
Yes: if not seq: if seq: No: if len(seq): if not len(seq):
我们应该期望标准库代码尽可能高效和正确。但为什么会这样?为什么我们需要这个指导?
解释
我经常会看到经验丰富的 Python 程序员写出这样的代码:
if len(a) == 0: # Don't do this!
print('a is an empty list')
而惰性语言的用户可能会倾向于这样做:
if a == []: # Don't do this!
print('a is an empty list')
这些在各自的其他语言中都是正确的。在 Python 中,这在语义上也是正确的。
但我们认为它不符合 Python 风格,因为 Python 通过布尔强制直接在列表对象的接口中支持这些语义。
来自文档(并特别注意包含空列表[]
):
默认情况下,除非对象类定义了
__bool__()
返回值的方法False
或__len__()
调用该对象时返回零的方法,否则该对象将被视为真。以下是大多数被视为假的内置对象:
定义为假的常量:
None
和False
。任何数字类型的零:
0
,0.0
,0j
,Decimal(0)
,Fraction(0, 1)
空序列和集合:
''
,,,,,,()
`[]{}
set()`range(0)
以及数据模型文档:
object.__bool__(self)
调用以执行真值测试和内置操作
bool()
;应返回False
或True
。当未定义此方法时,
__len__()
如果已定义,则调用 ,并且如果其结果非零,则认为对象为真。如果类既未定义 也__len__()
未定义__bool__()
,则其所有实例都被视为真。
和
object.__len__(self)
调用以实现内置函数
len()
。应返回对象的长度,一个 >= 0 的整数。此外,未定义方法__bool__()
且其__len__()
方法返回零的对象在布尔上下文中被视为 false。
所以不要这样:
if len(a) == 0: # Don't do this!
print('a is an empty list')
或这样:
if a == []: # Don't do this!
print('a is an empty list')
这样做:
if not a:
print('a is an empty list')
遵循 Python 规范通常能提高性能:
这值得吗?(请注意,执行等效操作的时间越少越好:)
>>> 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
为了便于衡量,以下是调用该函数以及构造和返回一个空列表的成本,您可以从上面使用的空度检查的成本中减去它:
>>> min(timeit.repeat(lambda: [], repeat=100))
0.07074015751817342
我们发现,使用内置函数检查长度或检查空列表的性能远低于使用文档中所述的语言内置语法。len
`0`
为什么?
对于len(a) == 0
支票:
首先,Python 必须检查全局变量是否len
被遮蔽。
然后它必须调用函数 load 0
,并在 Python 中(而不是用 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
并且[] == []
它必须构建一个不必要的列表,然后再次在 Python 的虚拟机中进行比较操作(与 C 相反)
>>> dis.dis(lambda: [] == [])
1 0 BUILD_LIST 0
2 BUILD_LIST 0
4 COMPARE_OP 2 (==)
6 RETURN_VALUE
由于列表的长度缓存在对象实例头中,“Pythonic”方式是一种更简单、更快速的检查:
>>> dis.dis(lambda: not [])
1 0 BUILD_LIST 0
2 UNARY_NOT
4 RETURN_VALUE
来自 C 源代码和文档的证据
PyVarObject
PyObject
这是添加字段的扩展ob_size
。这仅用于具有长度概念的对象。此类型在 Python/C API 中不常见。它对应于宏扩展定义的字段PyObject_VAR_HEAD
。
来自Include/listobject.h中的 c 源代码:
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
回复评论:
我想指出的是,这对于非空情况也是如此,尽管它非常丑陋,因为
l=[]
当时有%timeit len(l) != 0
90.6 ns ± 8.3 ns、%timeit l != []
55.6 ns ± 3.09、38.5%timeit not not l
ns ± 0.372。但尽管速度提高了三倍,也没有人会喜欢not not l
。这看起来很荒谬。但速度胜出,我想问题是用 timeit 进行测试,因为 just
if l:
就足够了,但令人惊讶的%timeit bool(l)
是产生了 101 ns ± 2.64 ns。有趣的是,没有办法在没有这个惩罚的情况下强制转换为 bool。%timeit l
是无用的,因为不会发生任何转换。
IPython magic%timeit
在这里并不是完全没用的:
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)
我们可以看到这里每增加一个,都会产生一些线性成本not
。我们希望看到成本,在其他条件不变的情况下,即在其他所有条件相同的情况下,尽可能地最小化其他所有条件:
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)
现在让我们看一下非空列表的情况:
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)
我们在这里可以看到,将实际值传递给条件检查还是将列表本身传递给条件检查都没有什么区别bool
,如果有的话,直接给出列表会更快。
Python 是用 C 编写的;它在 C 级别使用其逻辑。用 Python 编写的任何东西都会变慢。除非您直接使用 Python 内置的机制,否则速度可能会慢几个数量级。
解决方案 6:
空列表本身在真值测试中被视为假(参见python 文档):
a = []
if a:
print("not empty")
对于Daren Thomas 的回答:
编辑:另一个反对将空列表测试为 False 的观点是:多态性呢?您不应该依赖列表作为列表。它应该像鸭子一样嘎嘎叫 - 当它没有元素时,您如何让您的 duckCollection 嘎嘎叫“False”?
你的 duckCollection 应该实现__nonzero__
,__len__
这样 if a: 就可以正常工作。
解决方案 7:
Patrick 的(被接受的)答案是正确的:这if not a:
是正确的做法。Harley Holcombe 的答案是正确的,这是 PEP 8 风格指南中的内容。但是,没有一个答案解释为什么遵循这个习惯用法是个好主意 — — 即使你个人认为它不够明确或让 Ruby 用户感到困惑等等。
Python 代码和 Python 社区都有很强的习惯用法。遵循这些习惯用法可以让任何熟悉 Python 的人更容易阅读你的代码。而当你违反这些习惯用法时,这是一个强烈的信号。
确实,它if not a:
不区分空列表None
、数字 0、空元组、空的用户创建集合类型、空的用户创建的非集合类型,或充当具有 falsey 值的标量的单元素 NumPy 数组等。有时明确说明这一点很重要。在这种情况下,您知道要明确说明什么if not a and a is not None:
,因此您可以针对这一点进行测试。例如,表示“除 None 之外的任何 falsey”,而if len(a) != 0:
表示“仅空序列 - 除序列之外的任何东西都是错误”,等等。除了测试您想要测试的内容之外,这还向读者表明此测试很重要。
但是,当你没有任何需要明确说明的内容时,除此以外的任何内容if not a:
都会误导读者。你发出的信号是,某些内容很重要,但实际上并不重要。(你还可能使代码变得不那么灵活、更慢,或者其他什么,但这些都不那么重要。)如果你习惯性地以这种方式误导读者,那么当你确实需要做出区分时,读者将不会注意到,因为你一直在“谎报”你的代码。
解决方案 8:
为何要检查?
似乎没有人质疑您是否需要首先测试列表。由于您没有提供其他背景信息,我可以想象您可能首先不需要进行此检查,但不熟悉 Python 中的列表处理。
我认为最 Pythonic 的方式是根本不检查,而是只处理列表。这样,无论列表是空的还是满的,它都会做正确的事情。
a = []
for item in a:
# <Do something with item>
# <The rest of code>
这样做的好处是可以处理a的任何内容,而不需要专门检查是否为空。如果a为空,则依赖块将不会执行,解释器将转到下一行。
如果你确实需要检查数组是否为空:
a = []
if not a:
# <React to empty list>
# <The rest of code>
就足够了。
解决方案 9:
len()
对于 Python 列表、字符串、字典和集合而言,这是一个 O(1) 操作。Python 内部会跟踪这些容器中的元素数量。
JavaScript具有类似的真/假概念。
解决方案 10:
我曾写道:
if isinstance(a, (list, some, other, types, i, accept)) and not a:
do_stuff
投票结果为 -1。我不确定这是因为读者反对该策略还是认为所给出的答案没有帮助。我假装是后者,因为——无论什么算作“pythonic”——这都是正确的策略。除非您已经排除或准备处理例如的情况a
,否则False
您需要一个比仅仅更严格的测试if not a:
。您可以使用类似这样的测试:
if isinstance(a, numpy.ndarray) and not a.size:
do_stuff
elif isinstance(a, collections.Sized) and not a:
do_stuff
第一个测试是对上面@Mike 的回答的回应。第三行也可以替换为:
elif isinstance(a, (list, tuple)) and not a:
如果你只想接受特定类型(及其子类型)的实例,或者:
elif isinstance(a, (list, tuple)) and not len(a):
您可以不进行显式类型检查,但前提是周围环境已经向您保证这a
是您准备处理的类型的值,或者您确定您准备处理的类型将引发错误(例如,TypeError
如果您调用len
未定义的值),而您准备处理。一般来说,“pythonic”惯例似乎走最后这条路。像鸭子一样挤压它,如果它不知道如何嘎嘎叫,就让它引发 DuckError。不过,您仍然必须考虑您正在做出的类型假设,以及您不准备正确处理的情况是否真的会在正确的地方出错。Numpy 数组是一个很好的例子,仅仅盲目地依赖len
或布尔类型转换可能无法完全达到您的预期。
解决方案 11:
来自有关真值测试的文档:
除此处列出的值之外的所有值均视为True
None
False
任何数字类型的零,例如
0
,0.0
,0j
。任何空序列,例如
''
,()
,[]
。任何空映射,例如
{}
。用户定义类的实例,如果该类定义了
__bool__()
或__len__()
方法,则该方法返回整数零或布尔值False
。
正如所见,空列表[]
为假,因此执行对布尔值所执行的操作听起来最有效:
if not a:
print('"a" is empty!')
解决方案 12:
您可以使用以下几种方法检查列表是否为空:
a = [] #the list
1)非常简单的python方式:
if not a:
print("a is empty")
在 Python 中,空容器(例如列表、元组、集合、字典、变量等)被视为False
。可以简单地将列表视为谓词(返回布尔值)。True
值表示它非空。
2)一种更明确的方法:使用len()
来查找长度并检查它是否等于0
:
if len(a) == 0:
print("a is empty")
3)或者将其与匿名空列表进行比较:
if a == []:
print("a is empty")
4)另一种愚蠢的方法是使用exception
和iter()
:
try:
next(iter(a))
# list has elements
except StopIteration:
print("Error: a is empty")
解决方案 13:
我更喜欢以下内容:
if a == []:
print "The list is empty."
解决方案 14:
方法 1(首选):
if not a:
print ("Empty")
方法 2:
if len(a) == 0:
print("Empty")
方法 3:
if a == []:
print ("Empty")
解决方案 15:
您甚至可以尝试使用bool()
这样的方法。尽管它的可读性较差,但这确实是一种简洁的方法。
a = [1,2,3];
print bool(a); # it will return True
a = [];
print bool(a); # it will return False
我喜欢这种方式来检查清单是否为空。
非常方便且实用。
解决方案 16:
要检查列表是否为空,可以使用以下两种方法。但请记住,我们应该避免显式检查序列类型(这是一种不太 Pythonic 的方法):
def enquiry(list1):
return len(list1) == 0
list1 = []
if enquiry(list1):
print("The list isn't empty")
else:
print("The list is Empty")
# Result: "The list is Empty".
第二种方法更符合 Python风格。这种方法是一种隐式检查方法,比前一种方法更可取。
def enquiry(list1):
return not list1
list1 = []
if enquiry(list1):
print("The list is Empty")
else:
print("The list isn't empty")
# Result: "The list is Empty"
解决方案 17:
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])
有时最好None
分别测试 和 是否为空,因为这是两种不同的状态。上面的代码产生以下输出:
list is None
list is empty
list has 3 elements
尽管假值毫无意义None
。所以如果你不想单独测试假值None
,你不必这么做。
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])
产生预期
list is empty
list is empty
list has 3 elements
解决方案 18:
已经给出了很多答案,其中很多都很好。我只想补充一点,检查
not a
也会传递给None
其他类型的空结构。如果你真的想检查空列表,你可以这样做:
if isinstance(a, list) and len(a)==0:
print("Received an empty list")
解决方案 19:
如果你想检查列表是否为空:
l = []
if l:
# do your stuff.
如果你想检查列表中的所有值是否为空。但是True
对于空列表,它将是:
l = ["", False, 0, '', [], {}, ()]
if all(bool(x) for x in l):
# do your stuff.
如果您想同时使用这两种情况:
def empty_list(lst):
if len(lst) == 0:
return False
else:
return all(bool(x) for x in l)
现在您可以使用:
if empty_list(lst):
# do your stuff.
解决方案 20:
print('not empty' if a else 'empty')
更实际一点:
a.pop() if a else None
最短版本:
if a: a.pop()
解决方案 21:
我们可以使用简单的if else:
item_list=[]
if len(item_list) == 0:
print("list is empty")
else:
print("list is not empty")
解决方案 22:
受到dubiousjim 解决方案的启发,我建议使用额外的一般检查来判断它是否是可迭代的:
import collections
def is_empty(a):
return not a and isinstance(a, collections.Iterable)
注意:字符串被视为可迭代的——and not isinstance(a,(str,unicode))
如果希望排除空字符串,请添加
测试:
>>> 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
解决方案 23:
只需使用 is_empty() 或创建如下函数:-
def is_empty(any_structure):
if any_structure:
print('Structure is not empty.')
return True
else:
print('Structure is empty.')
return False
它可用于任何数据结构,如列表、元组、字典等。通过这些,您只需使用 即可多次调用它is_empty(any_structure)
。
解决方案 24:
简单的方法是检查长度是否等于零。
if len(a) == 0:
print("a is empty")
解决方案 25:
从 python3 开始你可以使用
a == []
检查列表是否为空
编辑:这也适用于python2.7。
我不知道为什么会有这么多复杂的答案。答案非常清晰直接
解决方案 26:
空列表的真值为 ,False
而非空列表的真值为True
。
解决方案 27:
我来这里是因为一个特殊的用例:我实际上想要一个函数来告诉我列表是否为空。我想避免在这里编写自己的函数或使用 lambda 表达式(因为它看起来应该足够简单):
foo = itertools.takewhile(is_not_empty, (f(x) for x in itertools.count(1)))
当然,有一个非常自然的方法可以做到这一点:
foo = itertools.takewhile(bool, (f(x) for x in itertools.count(1)))
当然,不要使用bool
in if
(即if bool(L):
),因为它是隐含的。但是,对于明确需要“不为空”作为函数的情况,bool
这是最佳选择。