Требуется только индекс: перечислить или (х) диапазон?
Если я хочу использовать только индекс в цикле, лучше ли мне использовать 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()
создает более богатую структуру данных, которую вы собираетесь немедленно выбросить.