Почему перечисление Python так медленно? - PullRequest
6 голосов
/ 30 августа 2009

Почему «перечислять» медленнее, чем «xrange + lst [i]»?


>>> from timeit import Timer
>>> lst = [1,2,3,0,1,2]*1000
>>> setup = 'from __main__ import lst'
>>> s1 = """
for i in range(len(lst)):
    elem = lst[i]
"""
>>> s2 = """
for i in xrange(len(lst)):
    elem = lst[i]
"""
>>> s3 = """
for i, v in enumerate(lst):
    elem = v
"""
>>> t1 = Timer(s1, setup); t2 = Timer(s2, setup); t3 = Timer(s3, setup)
>>> t1.timeit(3000), t2.timeit(3000), t3.timeit(3000)
(1.9263118636586494, 1.6119261665937992, 1.9606022553145719)
>>> t1.timeit(3000), t2.timeit(3000), t3.timeit(3000)
(1.93520258859715, 1.6145745478824836, 1.9529405971988041)

EDIT: Я имею в виду, почему

for i, v in enumerate(lst):
    elem = i, v
медленнее
for i in xrange(len(lst)):
    elem = i, lst[i]

Ответы [ 2 ]

15 голосов
/ 30 августа 2009

Если вы измерите должным образом, вы увидите, что по сути нет никакой разницы (в этом примере enumerate микроскопически быстрее, чем xrange, но в пределах шума):

$ python -mtimeit -s'lst=[1,2,3,0,1,2]*1000' 'for i in xrange(len(lst)): elem=lst[i]'
1000 loops, best of 3: 480 usec per loop
$ python -mtimeit -s'lst=[1,2,3,0,1,2]*1000' 'for i, elem in enumerate(lst): pass'
1000 loops, best of 3: 473 usec per loop

(Кстати, я всегда рекомендую использовать timeit в приглашении оболочки, как это, а не в коде или в приглашении интерпретатора, как вы делаете, просто потому, что вывод так хорошо отформатирован и удобен, с единицами измерения время и все).

В вашем коде у вас есть дополнительное назначение в случае перечисления: вы присваиваете элемент списка v в предложении заголовка for, а затем снова присваиваете v значение elem; тогда как в случае с xrange вы назначаете элемент только один раз, elem. В моем случае я также назначаю только один раз в любом случае, конечно; почему вы хотите назначить несколько раз в любом случае ?! Что бы вы ни делали с elem и i в теле цикла, вы можете сделать это одинаково в двух измеряемых мной формах, просто без избыточности, которую имеет ваш перечисляемый регистр.

5 голосов
/ 30 августа 2009

Возможно, потому что вы замучили enumerate. Попробуйте это:

>>> s3 = """
for i, elem in enumerate(lst):
    pass
"""

Обновление Две дополнительные причины использования timeit в приглашении оболочки, которые Алекс не упомянул:

(1) Это делает «лучше всего из N» для вас.
(2) Для вас выясняется, сколько итераций необходимо для получения значимого результата.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...