python设置空列表_python - 如何检查列表是否为空?

检查列表是否为空的最佳方法

例如,如果传递以下内容:

PyObject

如何检查a是否为空?

简答:

将列表放在布尔上下文中(例如,使用PyObject或ob_size语句)。 如果它是空的,它将测试PyObject_VAR_HEAD,否则测试__len__()。 例如:

if not a: # do this!

print('a is an empty list')

上诉到权威

PEP 8是Python标准库中Python代码的官方Python风格指南,断言:

对于序列,(字符串,列表,元组),请使用空序列为假的事实。

PyObject

我们应该期望标准库代码应该尽可能高效和正确。 但为什么会这样,为什么我们需要这个指导?

说明

我经常从经验丰富的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中甚至在语义上也是正确的。

但我们认为它不是Pythonic,因为Python通过布尔强制直接在列表对象的接口中支持这些语义。

从文档(并特别注意包含空列表,PyObject):

默认情况下,除非其类定义,否则将对象视为true   返回ob_size或PyObject_VAR_HEAD方法的PyObject方法   当使用对象调用时返回零。 以下是大多数被认为是错误的内置对象:

常量定义为false:PyObject和ob_size。

零的任何数字类型:PyObject,ob_size,PyObject_VAR_HEAD,__len__(),__len__()

空序列和集合:PyObject,ob_size,PyObject_VAR_HEAD,__len__(),__len__(),__bool__()

和数据模型文档:

PyObject

被称实施真值测试和内置操作PyObject; 应返回ob_size或PyObject_VAR_HEAD。未定义此方法时,   如果已定义,则调用__len__(),如果对象的结果非零,则认为该对象为true。 如果类既未定义__len__()   也没有__bool__(),它的所有实例都被认为是真的。

PyObject

被调用以实现内置函数PyObject。应该返回对象的长度,整数> = 0.此外,未定义ob_size方法且其PyObject_VAR_HEAD方法返回零的对象在一个被认为是假的 布尔上下文。

所以不是这样的:

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

对于比例,这是调用函数和构造并返回空列表的成本,您可以从上面使用的空白检查的成本中减去:

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

0.07074015751817342

我们看到,使用内置函数PyObject检查长度与ob_size相比或检查空列表要比使用所记录的语言的内置语法要低得多。

为什么?

对于PyObject检查:

首先Python必须检查全局变量以查看PyObject是否被遮蔽。

然后它必须调用该函数,加载PyObject,并在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

对于PyObject,它必须构建一个不必要的列表,然后再次在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源和文档的证据

PyObject

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

我很喜欢研究这个,我花了很多时间来策划我的答案。 如果您认为我要留下一些东西,请在评论中告诉我。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值