Требуется только индекс: перечислить или (х) диапазон?

Если я хочу использовать только индекс в цикле, лучше ли мне использовать range/xrange функция в сочетании с len()

a = [1,2,3]
for i in xrange(len(a)):
    print i 

или же enumerate? Даже если я не буду использовать p совсем?

for i,p in enumerate(a):
    print i    

8 ответов

Решение

Я хотел бы использовать enumerate поскольку он более универсален - например, он будет работать с итерациями и последовательностями, а издержки на простое возвращение ссылки на объект не так уж велики - пока xrange(len(something)) хотя (для меня) легче читать как ваше намерение - сломается на объектах без поддержки len...

Использование xrange с len - довольно распространенный случай, так что да, вы можете использовать его, если вам нужен только доступ к значениям по индексу.

Но если вы по какой-то причине предпочитаете использовать перечисление, вы можете использовать подчеркивание (_), это просто часто встречающаяся запись, показывающая, что вы не будете использовать переменную каким-либо осмысленным образом:

for i, _ in enumerate(a):
    print i

Есть также ловушка, которая может произойти при использовании подчеркивания (_). Также часто называют "переводящие" функции как _ в библиотеках и системах i18n, поэтому будьте осторожны, чтобы использовать их с gettext или какой-либо другой библиотекой такого рода (спасибо @lazyr).

Это редкое требование - единственная информация, используемая из контейнера, это его длина! В этом случае я бы действительно сделал этот факт явным и использовал бы первую версию.

xrange должен быть немного быстрее, но перечисление будет означать, что вам не нужно менять его, когда вы понимаете, что вам нужно p в конце концов

Я провел временной тест и обнаружил, что диапазон примерно в 2 раза быстрее, чем перечислять. (на python 3.6 для Win32)

лучшее из 3, для len(a) = 1M

  • перечислить (а): 0,125 с
  • диапазон (len(a)): 0,058 с

Надеюсь, поможет.

К вашему сведению: я изначально начал этот тест, чтобы сравнить скорость Python с VBA... и обнаружил, что VBA на самом деле в 7 раз быстрее, чем метод диапазона... это из-за моих слабых навыков Python?

конечно, Python может сделать лучше, чем VBA как-то

скрипт для перечисления

import time
a = [0]
a = a * 1000000
time.perf_counter()

for i,j in enumerate(a):
    pass

print(time.perf_counter())

скрипт для диапазона

import time
a = [0]
a = a * 1000000
time.perf_counter()

for i in range(len(a)):
    pass

print(time.perf_counter())

скрипт для vba (0.008s)

Sub timetest_for()
Dim a(1000000) As Byte
Dim i As Long
tproc = Timer
For i = 1 To UBound(a)
Next i
Debug.Print Timer - tproc
End Sub

Я написал это, потому что я хотел проверить это. Так что это зависит от того, нужны ли вам значения для работы.

Код:

testlist = []
for i in range(10000):
    testlist.append(i)

def rangelist():
    a = 0
    for i in range(len(testlist)):
        a += i
        a = testlist[i] + 1   # Comment this line for example for testing

def enumlist():
    b = 0
    for i, x in enumerate(testlist):
        b += i
        b = x + 1   # Comment this line for example for testing

import timeit
t = timeit.Timer(lambda: rangelist())
print("range(len()):")
print(t.timeit(number=10000))
t = timeit.Timer(lambda: enumlist())
print("enum():")
print(t.timeit(number=10000))

Теперь вы можете запустить его и, скорее всего, получите результат, что enum() быстрее. Когда вы комментируете источник на a = testlist[i] + 1 а также b = x + 1 Вы увидите, что диапазон (len()) быстрее.

Для кода выше я получаю:

range(len()):
18.766527627612255
enum():
15.353173553868345

Теперь, комментируя, как указано выше, я получаю:

range(len()):
8.231641875551514
enum():
9.974262515773656

Основываясь на вашем примере кода,

res = [[profiel.attr[i].x for i,p in enumerate(profiel.attr)] for profiel in prof_obj]

Я бы заменил его

res = [[p.x for p in profiel.attr] for profiel in prof_obj]

Просто используйте range(), Если вы все равно собираетесь использовать все индексы, xrange() не дает никакой реальной выгоды (если len(a) действительно большой). А также enumerate() создает более богатую структуру данных, которую вы собираетесь немедленно выбросить.

Другие вопросы по тегам