小编典典

为什么“ any()”比使用循环慢?

python

我一直在一个项目中工作,该项目管理大量的单词列表,并通过大量测试使它们通过,以验证列表中的每个单词是否正确。有趣的是,每当我使用“更快”的工具(如itertools模块)时,它们似乎就会变慢。

最后,我决定问这个问题,因为我可能做错了什么。以下代码将尝试测试any()函数的性能与使用循环的关系。

#!/usr/bin/python3
#

import time
from unicodedata import normalize


file_path='./tests'


start=time.time()
with open(file_path, encoding='utf-8', mode='rt') as f:
    tests_list=f.read()
print('File reading done in {} seconds'.format(time.time() - start))

start=time.time()
tests_list=[line.strip() for line in normalize('NFC',tests_list).splitlines()]
print('String formalization, and list strip done in {} seconds'.format(time.time()-start))
print('{} strings'.format(len(tests_list)))


unallowed_combinations=['ab','ac','ad','ae','af','ag','ah','ai','af','ax',
                        'ae','rt','rz','bt','du','iz','ip','uy','io','ik',
                        'il','iw','ww','wp']


def combination_is_valid(string):
    if any(combination in string for combination in unallowed_combinations):
        return False

    return True


def combination_is_valid2(string):
    for combination in unallowed_combinations:
        if combination in string:
            return False

    return True


print('Testing the performance of any()')

start=time.time()
for string in tests_list:
    combination_is_valid(string)
print('combination_is_valid ended in {} seconds'.format(time.time()-start))


start=time.time()
for string in tests_list:
    combination_is_valid2(string)
print('combination_is_valid2 ended in {} seconds'.format(time.time()-start))

前面的代码很能代表我所做的测试,如果我们看一下结果,则可以:

File reading done in 0.22988605499267578 seconds
String formalization, and list strip done in 6.803032875061035 seconds
38709922 strings
Testing the performance of any()
combination_is_valid ended in 80.74802565574646 seconds
combination_is_valid2 ended in 41.69514226913452 seconds


File reading done in 0.24268722534179688 seconds
String formalization, and list strip done in 6.720442771911621 seconds
38709922 strings
Testing the performance of any()
combination_is_valid ended in 79.05265760421753 seconds
combination_is_valid2 ended in 42.24800777435303 seconds

我发现使用循环比使用快一半,这有点令人惊讶any()。对此有什么解释?难道我做错了什么?

(我在GNU-Linux下使用python3.4)


阅读 135

收藏
2021-01-20

共1个答案

小编典典

实际上该any()功能等于以下功能:

def any(iterable):
    for element in iterable:
        if element:
            return True
    return False

这就像您的第二个函数,但是由于any()返回本身是布尔值,因此您无需检查结果然后返回新值,所以性能的差异是因为您实际上使用了冗余返回和if条件,还调用了any内部另一个函数。

因此,any这里的优点是您不需要用另一个函数包装它,因为它可以为您完成所有事情。

就像@interjay在评论中提到的那样,似乎我最想念的最重要的原因是您将生成器表达式传递给了any()它,它不会立即提供结果,并且由于它按需产生结果,因此它会做额外的工作。

基于PEP 0289-生成器表达式

生成器表达式的语义等同于创建匿名生成器函数并对其进行调用。例如:

g = (x**2 for x in range(10))
print g.next()

等效于:

def __gen(exp):
    for x in exp:
        yield x**2
g = __gen(iter(range(10)))
print g.next()

因此,如您所见,每次python要访问下一个项目时,它都会调用生成器的iter函数和next方法,最后结果是any()在这种情况下使用它是过分的。

2021-01-20