我想知道python解释器会自动完成哪种类型的优化。例如,我有以下代码来检查字符串是否以startList
:中的任何子字符串开头
def startswithAny(string, startList):
return any([string.startswith(x) for x in startList])
假设startList
包含1000个条目,但string.startswith(startList[0])
已经生成true。会发生什么?[string.startswith(x) for x in startList]
还会被全面评估吗?或者解释器会识别出any((已经为true了吗?
如果没有,那么比IMHO更有意义的是编写这样的非Python代码,比如:
def startswithAny(string, startList):
for x in startList:
if string.startswith(x):
return True
return False
感谢
好吧,any
将接受短路。问题是,当您使用列表时,您首先计算完整列表,然后才对完整列表调用any
。
如果你真的想使用短路,你应该使用生成器而不是列表:
def startswithAny(string, startList):
return any((string.startswith(x) for x in startList))
(方括号替换为括号(
使用timeit演示:
>>> timeit.timeit('any([i.startswith("ab") for i in lst])',
'lst = [ "abc" + str(i) for i in range(10000)]', number=10000)
17.005268767956352
>>> timeit.timeit('any((i.startswith("ab") for i in lst))',
'lst = [ "abc" + str(i) for i in range(10000)]', number=10000)
0.006302962841857607
是的,any
函数被保证短路,这意味着当它找到一个为True的元素时,它就终止了。any()
代码本质上等效于以下代码:
def any(iterable):
for element in iterable:
if element:
return True
return False
正如您所看到的,当一个元素为True时,循环就会停止。
所以,是的,你最后写的代码本质上相当于在上面运行any()
。any()
是一种更Python的方式。
根据文件,any
保证短路。
但是你的使用会破坏这种优化,因为列表理解表达式会对每个元素进行求值,所以你应该传递一个生成器表达式,这意味着更优化的方法是any(string.startswith(x) for x in startList)