Некоторые измерения производительности, используя timeitвместо того, чтобы пытаться сделать это вручную time.
Во-первых, Apple 2.7.2 64-битная:
In [37]: %timeit collections.deque((x for x in xrange(10000000) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.05 s per loop
Теперь python.org 3.3.0 64-bit:
In [83]: %timeit collections.deque((x for x in range(10000000) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.32 s per loop
In [84]: %timeit collections.deque((x for x in xrange(10000000) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.31 s per loop
In [85]: %timeit collections.deque((x for x in iter(range(10000000)) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.33 s per loop
По- видимому, 3.x rangeдействительно немного медленнее , чем 2.x xrange. И xrangeфункция ОП не имеет к этому никакого отношения. (Не удивительно, поскольку одноразовый вызов в __iter__слот вряд ли будет виден среди 10000000 вызовов, что бы ни происходило в цикле, но кто-то поднял это как возможность.)
Но это только на 30% медленнее. Как ОП получил 2x как медленный? Что ж, если я повторю те же тесты с 32-битным Python, я получу 1,58 против 3,12. Поэтому я предполагаю, что это еще один из тех случаев, когда 3.x был оптимизирован для 64-битной производительности таким образом, что это наносит ущерб 32-битной системе.
Но действительно ли это имеет значение? Проверьте это, с 3.3.0 64-битными снова:
In [86]: %timeit [x for x in range(10000000) if x%4 == 0]
1 loops, best of 3: 3.65 s per loop
Таким образом, сборка listзанимает более чем вдвое больше времени, чем вся итерация.
А что касается «потребляет гораздо больше ресурсов, чем Python 2.6+», то из моих тестов похоже, что 3.x rangeточно такого же размера, что и 2.x xrange- и, даже если он в 10 раз больше, создает ненужный список все еще на 10000000 раз больше проблем, чем любая другая итерация диапазона.
А как насчет явного forцикла вместо цикла C внутри deque?
In [87]: def consume(x):
....: for i in x:
....: pass
In [88]: %timeit consume(x for x in range(10000000) if x%4 == 0)
1 loops, best of 3: 1.85 s per loop
Таким образом, на forутверждение тратится почти столько же времени, сколько и на реальную работу по итерации range.
Если вы беспокоитесь об оптимизации итерации объекта диапазона, вы, вероятно, смотрите не в том месте.
Между тем вы продолжаете спрашивать, почему xrangeбыл удален, независимо от того, сколько раз люди говорили вам одно и то же, но я повторю это еще раз: он не был удален: он был переименован range, а 2.x range- это то, что было удалено.
Вот некоторые доказательства того, что rangeобъект 3.3 является прямым потомком xrangeобъекта 2.x (а не rangeфункции 2.x ): источник 3.3range и 2.7xrange . Вы даже можете увидеть историю изменений (я думаю, что она связана с изменением, которое заменило последний экземпляр строки «xrange» в любом месте файла).
Итак, почему это медленнее?
Ну, например, они добавили много новых функций. С другой стороны, они сделали все виды изменений повсеместно (особенно внутри итерации), которые имеют незначительные побочные эффекты. И было проделано много работы, чтобы значительно оптимизировать различные важные случаи, даже если иногда они слегка пессимизируют менее важные случаи. Добавьте все это, и я не удивлен, что итерация rangeкак можно быстрее теперь немного медленнее. Это один из тех менее важных случаев, на которых никто никогда не будет обращать внимания. Ни у кого, вероятно, никогда не будет реального сценария использования, где эта разница в производительности является горячей точкой в их коде.
rangeв Python 3.x взятxrangeиз Python 2.x. Это был фактически Python 2.x,rangeкоторый был удален.