使用enumerate的好处是什么?

5

我是Python的初学者。 我想知道,使用enumerate是否是更有效的方法?或者只有在处理更复杂的内容时才会发挥作用,而对于这里并不太重要?

没有使用enumerate的代码:

for x in thing:
    if thing.index(x) % 2 == 0:
        x += 7
        print (x)
    else:
        print (x)

我的代码使用enumerate:

for index,x in enumerate(thing):
    if index % 2 == 0:
        x += 7
        print (x)
    else:
        print (x)

1
你有点自己回答了你的问题... :-) 如你所见,在第一个代码片段中,你必须使用一个非常低效的函数(thing.index(x),其执行时间为O(n),如此解释:https://dev59.com/b2025IYBdhLWcg3wl3K-),以便在数组`thing`中获取`x`的索引。你在每个单独的`for`循环迭代中都这样做,而在第二个代码片段中,你直接获取索引。 - Savir
2
这两个代码的功能不同 - 请尝试 thing = [1,1] - 因此它们不是一个好的比较。 - DSM
太对了!! @DSM说得非常正确... 在他的例子中,thing.index(1)总是会返回0,因为index函数返回第一个匹配项的索引。而enumerate会遍历整个数组,在@DSM的例子中给出01 - Savir
2个回答

10

list.index的复杂度为O(n),这意味着您将多次遍历列表(考虑到for循环本身),它返回给定项的第一个索引,这意味着对于具有重复项的列表,您将得到不正确的结果。

enumerate通过即时生成索引和项来解决这个问题; 我认为你无法获得比内置的enumerate提供的性能更好的性能。

还要记住,enumerate是惰性评估的; 对于大型列表来说,这是一个巨大的优势。相反地,即使列表中没有重复项并且结果正确,您也不希望调用一个大型列表的index方法,因为您仍然会在列表上进行不必要的遍历。


而且不需要仅仅循环索引,然后使用它访问元素(这会导致很多烦人的样板文件)。 - jpmc26
@jpmc26 是的,这也是。当我们需要索引和项时,“range(len(...))”可能会被视为代码异味。 - Moses Koledoye

1
如果您想了解效率问题,有几种工具可以用来检查哪种解决方案/算法更高效。这被称为“分析”。

分析的第一个目的是测试代表性系统,以确定什么是缓慢的(或使用太多RAM、造成过多的磁盘I/O或网络I/O)。

分析通常会增加开销(10倍到100倍的减速可能很典型),而您仍然希望您的代码尽可能类似于在实际情况下使用。提取一个测试用例并隔离需要测试的系统部分。最好已经编写了自己的一组模块。

基本技术包括IPython中的“%timeit”魔法、“time.time()”和一个计时装饰器(见下面的示例)。您可以使用这些技术来理解语句和函数的行为。

然后你有“cProfile”,它将给你一个高层次的视图,让你可以将注意力集中在关键函数上。

接下来,看看line_profiler,它将基于每行进行函数分析。结果将包括每行被调用的次数和在每行上花费的时间百分比。这正是您需要了解哪些内容运行缓慢以及原因的信息。 perf stat可以帮助您了解最终在CPU上执行的指令数量以及CPU缓存的利用效率。这允许对矩阵操作进行高级调整。 heapy可以跟踪Python内存中的所有对象。这非常适用于查找奇怪的内存泄漏。如果您正在处理长时间运行的系统,则dowser会引起您的兴趣:它允许您通过Web浏览器界面内省长时间运行的进程中的活动对象。
为了帮助您了解为什么RAM使用量很高,请查看memory_profiler。它特别适用于在标记图表上随时间跟踪RAM使用情况,因此您可以向同事(或自己)解释为什么某些功能使用的RAM比预期更多。 示例:定义装饰器以自动化计时测量
from functools import wraps

def timefn(fn):
    @wraps(fn)
    def measure_time(*args, **kwargs):
        t1 = time.time()
        result = fn(*args, **kwargs)
        t2 = time.time()
        print ("@timefn:" + fn.func_name + " took " + str(t2 - t1) + " seconds")
        return result
    return measure_time

@timefn
def your_func(var1, var2):
    ...

如果需要更多信息,我建议阅读High performance Python(Micha Gorelick; Ian Ozsvald),上述内容来源于此。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接