我已经养成了使用 any() 来避免“elif hell”的习惯,我一直想知道它是否会影响我的代码。特别是在 for 循环中使用时。
经过测试,大多数情况下速度相似,但有时会快 50% 以上?
有熟悉幕后情况的人知道发生了什么吗?
设置:
import random
import string
from time import perf_counter
from typing import TypedDict
class Data(TypedDict):
name: str
value: int
print("start data")
huge_data: Data = {
"key" + random.choice(string.printable): random.randrange(1_000)
for _ in range(1_000_000)
}
print("start test\n")
“elif hell”示例:
start_00 = perf_counter()
for key, value in huge_data.items():
if key.isalpha():
continue
elif key[-1].isdigit():
continue
elif value not in range(3, 1_000, 3):
continue
elif value % 2 != 0:
continue
print("00", key, value)
time_00 = perf_counter() - start_00
我一直在做什么:
start_01 = perf_counter()
for key, value in huge_data.items():
condition_list = [
key.isalpha(),
key[-1].isdigit(),
value not in range(3, 1_000, 3),
value % 2 != 0,
]
if any(condition_list):
continue
print("01", key, value)
time_01 = perf_counter() - start_01
输出: 1:
start data
start test
00 key" 492
00 key. 942
00 key\ 378
00 key# 348
01 key" 492
01 key. 942
01 key\ 378
01 key# 348
Results:
time_00 = 0.00029450000000008636
time_01 = 0.0003111000000000086
2:
start data
start test
00 key= 354
00 key? 840
00 key[ 804
00 key_ 606
00 key> 564
00 key< 564
01 key= 354
01 key? 840
01 key[ 804
01 key_ 606
01 key> 564
01 key< 564
Results:
time_00 = 0.0004585999999999757
time_01 = 0.0004596999999999518
3:
start data
start test
00 key} 678
00 key{ 558
00 key& 732
01 key} 678
01 key{ 558
01 key& 732
Results:
time_00 = 0.000256800000000057
time_01 = 0.00027639999999995446
any() 方法更快:0.00011
start data
start test
00 key' 114
00 key* 426
00 key@ 936
00 key 960
00 key/ 390
00 key, 42
00 key\ 696
00 key% 414
00 key] 648
01 key' 114
01 key* 426
01 key@ 936
01 key 960
01 key/ 390
01 key, 42
01 key\ 696
01 key% 414
01 key] 648
Results:
time_00 = 0.0007916999999999508
time_01 = 0.0006793999999999967
any() 方法更快:0.00038
start data
start test
00 key] 846
00 key| 762
00 key 570
00 key^ 90
00 key? 30
00 key, 240
01 key] 846
01 key| 762
01 key 570
01 key^ 90
01 key? 30
01 key, 240
Results:
time_00 = 0.0008430999999999855
time_01 = 0.0004606000000000332
几乎每个逐个遍历一组值的内置操作都使用迭代协议。 Any()、all()、sum()、min()、max() 等都在幕后执行此操作。您可以使用 for 循环在 python 级别实现迭代协议,或者使用内置函数、列表理解等在解释器级别实现迭代协议。解释器总是更快,因为它以 C 速度执行。
请参阅下面具有相同功能的示例,一个使用 for 循环实现,另一个使用列表理解实现。两者产生相同的结果,但列表理解的速度大约快 20%。
from timeit import Timer
def for_loop():
result = []
for item in range(100000):
if item % 2 == 0:
result.append(item)
return result
def list_comprehension():
return [item for item in range(100000) if item % 2 == 0]
res_for = for_loop()
rest_lc = list_comprehension()
print(res_for == rest_lc)
print(Timer(for_loop).timeit(1000))
print(Timer(list_comprehension).timeit(1000))