例如,如果通过以下步骤:

a = []

如何检查a是否为空?


当前回答

受到dubiusjim解决方案的启发,我建议使用一个额外的常规检查,看看它是否可以迭代:

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

注意:如果希望排除空字符串,则字符串被认为是可迭代的add,而不是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

其他回答

已经给出了很多答案,其中很多都很好。我只是想加上那张支票

not a

也将通过None和其他类型的空结构。如果您确实想检查空列表,可以执行以下操作:

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

更实用一点:

a.pop() if a else None

最短版本:

if a: a.pop() 

我更喜欢以下内容:

if a == []:
   print "The list 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内置的机制,否则它可能会慢几个数量级。

我曾写道:

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

投票结果为-1。我不确定这是否是因为读者反对这一策略,或者认为答案没有帮助。我会假装是后者,因为——无论什么叫做“蟒蛇”——这是正确的策略。除非你已经排除了,或者已经准备好处理a为False的情况,否则你需要一个比不是:更严格的测试。你可以用这样的方法:

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是您准备处理的类型的值,或者如果您确定您不准备处理的那些类型将引发您准备好处理的错误(例如,如果您在未定义的值上调用len,则为TypeError)。总的来说,“蟒蛇”习俗似乎走到了最后一条路。像鸭子一样挤压它,如果它不知道如何呱呱叫,就让它养一只鸭子。不过,你仍然需要考虑你正在做什么样的假设,以及你没有准备好正确处理的案例是否真的会在正确的地方出错。Numpy数组是一个很好的例子,其中仅仅盲目地依赖len或布尔类型转换可能无法实现预期的效果。