例如,如果通过以下步骤:
a = []
如何检查a是否为空?
例如,如果通过以下步骤:
a = []
如何检查a是否为空?
当前回答
print('not empty' if a else 'empty')
更实用一点:
a.pop() if a else None
最短版本:
if a: a.pop()
其他回答
if not a:
print("List is empty")
使用空列表的隐含布尔性是相当Python的。
来自真实值测试的文档:
此处列出的值以外的所有值均视为True
没有一个错误任何数字类型的零,例如0、0.0、0j。任何空序列,例如“”、()、[]。任何空映射,例如{}。如果类定义了__bool_()或__len__()方法,则该方法返回整数零或布尔值False。
可以看出,空列表[]是错误的,因此对布尔值执行操作听起来最有效:
if not a:
print('"a" is empty!')
检查列表是否为空的最佳方法例如,如果通过以下步骤:a=[]如何检查a是否为空?
简短回答:
将列表放在布尔上下文中(例如,使用if或while语句)。如果为空,则测试False,否则测试True。例如:
if not a: # do this!
print('a is an empty list')
第8段
PEP8是Python标准库中Python代码的官方Python风格指南,它断言:
对于序列(字符串、列表、元组),请使用空序列为false的事实。是:如果不是seq:如果seq:否:如果len(seq):如果不是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通过布尔强制在列表对象的接口中直接支持这些语义。
从文档中(并特别注意空列表的包含,[]):
默认情况下,除非对象的类定义返回False的__bool__()方法或__len__()方法当使用对象调用时,返回零。以下是大多数被认为是假的内置对象:常量定义为false:None和false。任何数字类型的零:0,0.0,0j,十进制(0),分数(0,1)空序列和集合:“”,(),[],{},set(),range(0)
以及数据模型文档:
对象__布尔_(自身)调用以实现真值测试和内置操作bool();应返回False或True。当未定义该方法时,__如果定义了len__(),则调用它,如果结果为非零,则该对象视为真。如果类既没有定义__len__()也不是__bool_(),它的所有实例都被认为是真的。
and
对象__len__(自己)调用以实现内置函数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')
做Pythonic通常会在表演中获得回报:
它有回报吗?(请注意,执行等效操作的时间越短越好:)
>>> 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
对于scale,这里是调用函数、构造和返回空列表的成本,您可以从上面使用的空检查的成本中减去该成本:
>>> min(timeit.repeat(lambda: [], repeat=100))
0.07074015751817342
我们看到,使用内置函数len(与0相比)检查长度,或者检查空列表,都比使用所记录的语言的内置语法性能差得多。
Why?
对于len(a)==0,检查:
首先,Python必须检查全局变量,以查看len是否被隐藏。
然后,它必须调用函数,加载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=[],然后%timeitlen(l)!=0 90.6纳秒±8.3纳秒,%时间l!=[]55.6 ns±3.09,%时间不超过38.5 ns±0.372。但是,尽管速度是原来的三倍,但没有人会喜欢我。这看起来很可笑。但速度取胜我想问题是用timeit测试,因为仅当l:足够,但令人惊讶的是%timeit bool(l)产生101 ns±2.64 ns。有趣的是,如果没有这种惩罚,就没有办法强迫发出嘘声。%时间是无用的,因为不会发生转换。
IPython魔法%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)
我们可以看到,每增加一项都会有一点线性成本。我们希望看到成本相同,也就是说,所有其他方面都是平等的——所有其他方面尽可能最小化:
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)
我们在这里看到的是,无论是将实际布尔值传递给条件检查还是传递给列表本身,都没有什么不同,如果有什么不同的话,那么给出列表的速度会更快。
Python是用C编写的;它使用C级的逻辑。用Python编写的任何内容都会比较慢。除非您直接使用Python内置的机制,否则它可能会慢几个数量级。
如果要检查列表是否为空:
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.
让我来到这里的是一个特殊的用例:我实际上想要一个函数来告诉我列表是否为空。我想避免在这里编写自己的函数或使用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)))
当然,不要在if(即if bool(L):)中使用bool,因为它是隐含的。但是,对于明确需要“不为空”作为函数的情况,bool是最佳选择。