Python 中的any() 的“幕后”发生了什么?

问题描述 投票:0回答:1

我已经养成了使用 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
python dictionary cpython built-in
1个回答
0
投票

几乎每个逐个遍历一组值的内置操作都使用迭代协议。 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))
© www.soinside.com 2019 - 2024. All rights reserved.