我有以下列表
x = [1,2,3]
if x:
dosomething()
if len(x)>0:
dosomething()
在上面的例子中,如果语句会更快?
如果x
list
,则(从结果来看)没有区别。但是第一个要快一些:
%%timeit
if x:
pass
10000000 loops, best of 3: 95 ns per loop
比第二个:
%%timeit
if len(x) > 0:
pass
1000000 loops, best of 3: 276 ns per loop
在几乎所有情况下,您都应该将第一个与if x
一起使用。只有当你想区分None
、False
和空list
(或类似的东西)时,你才可能需要别的东西。
第一个语句会更快,因为它不需要执行函数,而在第二个语句中,在运行之前需要执行某些内容,在这种情况下len(x)
。
在内部,
if x:
将获取列表对象的大小,并检查它是否为非零值。
在这种情况下,
if len(x) > 0:
你正在明确地这样做。
此外,PEP-0008 建议第一种形式,
对于序列(字符串、列表、元组),请使用空序列为假的事实。
Yes: if not seq: if seq: No: if len(seq) if not len(seq)
@thefourtheye扩展答案,这里有一个演示/证明,当您检查列表的真值时调用__len__
:
>>> class mylist(list):
... def __len__(self):
... print('__len__ called')
... return super(mylist, self).__len__()
...
>>> a = mylist([1, 2, 3])
>>> if a:
... print('doing something')
...
__len__ called
doing something
>>>
>>> if len(a) > 0:
... print('doing something')
...
__len__ called
doing something
>>>
>>> bool(a)
__len__ called
True
这是一个快速的时机:
In [3]: a = [1,2,3]
In [4]: timeit if a: pass
10000000 loops, best of 3: 28.2 ns per loop
In [5]: timeit if len(a) > 0: pass
10000000 loops, best of 3: 62.2 ns per loop
因此,隐式检查稍微快一些(可能是因为全局len
函数没有开销),并且正如 PEP-0008 已经提到的。
如果您查看每种方法的dis.dis()
,您会发现第二种方法必须执行的步骤几乎是第一种方法的两倍。
In [1]: import dis
In [2]: def f(x):
....: if x: pass
....:
In [3]: def g(x):
....: if len(x) > 0: pass
....:
In [4]: dis.dis(f)
2 0 LOAD_FAST 0 (x)
3 POP_JUMP_IF_FALSE 9
6 JUMP_FORWARD 0 (to 9)
>> 9 LOAD_CONST 0 (None)
12 RETURN_VALUE
In [5]: dis.dis(g)
2 0 LOAD_GLOBAL 0 (len)
3 LOAD_FAST 0 (x)
6 CALL_FUNCTION 1
9 LOAD_CONST 1 (0)
12 COMPARE_OP 4 (>)
15 POP_JUMP_IF_FALSE 21
18 JUMP_FORWARD 0 (to 21)
>> 21 LOAD_CONST 0 (None)
24 RETURN_VALUE
他们都需要做LOAD_FAST
、POP_JUMP_IF_FALSE
、JUMP_FORWARD
、LOAD_CONST
和RETURN_VALUE
。但是第二种方法还需要做 LOAD_GLOBAL
、CALL_FUNCTION
、LOAD_CONST
和COMPARE_OP
。因此,第一种方法会更快。
然而,实际上,这两种方法之间的时间差异非常小,除非这些 if 语句在代码中运行数百万次,否则它不会明显影响程序的性能。对我来说,这听起来像是过早优化的一个例子。