Відповіді:
У Python 2.x:
range
створює список, тож якщо ви range(1, 10000000)
це робите, він створює список в пам'яті з 9999999
елементами.
xrange
є об'єктом послідовності, який оцінюється ліниво.
У Python 3 range
є еквівалент python's xrange
, і щоб отримати список, ви повинні використовувати list(range(...))
.
xrange(x).__iter__()
є генератором.
i
оцінюється на вимогу, а не на ініціалізацію.
range створює список, тож якщо ви
range(1, 10000000)
це робите, це створює список у пам'яті з9999999
елементами.
xrange
є генератором, тожоб'єктом послідовностієте, що оцінюється ліниво.
Це правда, але в Python 3 .range()
буде реалізований Python 2 .xrange()
. Якщо вам потрібно створити список, вам потрібно буде зробити:
list(range(1,100))
xrange
генератора? Це функція, що містить yield
оператор, і згідно з глосарієм такі функції називаються генераторами.
Пам'ятайте, використовуйте timeit
модуль, щоб перевірити, який з маленьких фрагментів коду швидше!
$ python -m timeit 'for i in range(1000000):' ' pass'
10 loops, best of 3: 90.5 msec per loop
$ python -m timeit 'for i in xrange(1000000):' ' pass'
10 loops, best of 3: 51.1 msec per loop
Особисто я завжди використовую .range()
, якщо не маю справу з дійсно величезними списками - як ви бачите, за часом, для списку мільйона записів, додаткові накладні витрати - всього 0,04 секунди. І як зазначає Corey, в Python 3.0 .xrange()
піде все-таки і .range()
надасть вам приємного поведінки ітератора.
python -m timeit "for i in xrange(1000000):" " pass"
the extra overhead is only 0.04 seconds
не правильний спосіб його погляду, (90.5-51.1)/51.1 = 1.771 times slower
це правильне, оскільки воно свідчить про те, що якщо це основний цикл вашої програми, він може потенційно вузьким місцем. Однак, якщо це невелика частина, то 1,77x не дуже.
xrange
зберігає лише параметри діапазону та генерує номери за запитом. Однак C-реалізація Python в даний час обмежує свої аргументи на C longs:
xrange(2**32-1, 2**32+1) # When long is 32 bits, OverflowError: Python int too large to convert to C long
range(2**32-1, 2**32+1) # OK --> [4294967295L, 4294967296L]
Зауважте, що в Python 3.0 є лише range
і він поводиться як 2.x, xrange
але без обмежень на мінімальну та максимальну кінцеві точки.
xrange повертає ітератор і одночасно зберігає лише одне число. діапазон зберігає весь список номерів у пам'яті.
xrange
нічого НЕ повертає ітератор.
and only keeps one number in memory at a time
а де розміщені інші, будь ласка, направляйте мене ..
Проведіть деякий час з довідкою про бібліотеку . Чим більше ви з цим знайомі, тим швидше ви зможете знайти відповіді на подібні питання. Особливо важливими є перші кілька глав про вбудовані об'єкти та типи.
Перевага типу xrange полягає в тому, що об’єкт xrange завжди займе однаковий об'єм пам'яті, незалежно від розміру діапазону, який він представляє. Немає послідовних переваг у виконанні.
Інший спосіб знайти швидку інформацію про конструкцію Python - це docstring та довідкова функція:
print xrange.__doc__ # def doc(x): print x.__doc__ is super useful
help(xrange)
Я вражений, що ніхто не читав doc :
Ця функція дуже схожа на
range()
, але повертаєxrange
об'єкт замість списку. Це непрозорий тип послідовностей, який дає ті самі значення, що і відповідний список, фактично не зберігаючи їх одночасно. Перевагаxrange()
надrange()
мінімальною (оскількиxrange()
все-таки доводиться створювати значення, коли їх запитують), за винятком випадків, коли на машині з голодом пам’яті використовується дуже великий діапазон або коли всі елементи діапазону ніколи не використовуються (наприклад, коли цикл є зазвичай припиняєтьсяbreak
).
діапазон створює список, тож якщо ви робите діапазон (1, 10000000), він створює список у пам'яті з 10000000 елементами. xrange - це генератор, тому він ліниво оцінює.
Це приносить вам дві переваги:
MemoryError
.Ви знайдете перевагу xrange
над range
на цьому простому прикладі:
import timeit
t1 = timeit.default_timer()
a = 0
for i in xrange(1, 100000000):
pass
t2 = timeit.default_timer()
print "time taken: ", (t2-t1) # 4.49153590202 seconds
t1 = timeit.default_timer()
a = 0
for i in range(1, 100000000):
pass
t2 = timeit.default_timer()
print "time taken: ", (t2-t1) # 7.04547905922 seconds
Наведений вище приклад не відображає нічого істотно кращого у випадку xrange
.
Тепер подивимось на такий випадок, де range
насправді дуже повільно, порівняно з xrange
.
import timeit
t1 = timeit.default_timer()
a = 0
for i in xrange(1, 100000000):
if i == 10000:
break
t2 = timeit.default_timer()
print "time taken: ", (t2-t1) # 0.000764846801758 seconds
t1 = timeit.default_timer()
a = 0
for i in range(1, 100000000):
if i == 10000:
break
t2 = timeit.default_timer()
print "time taken: ", (t2-t1) # 2.78506207466 seconds
З range
, він вже створює список від 0 до 100000000 (забирає багато часу), але xrange
є генератором, і він генерує лише числа залежно від потреби, тобто якщо ітерація триває.
У Python-3 реалізація range
функціоналу така сама, як і xrange
в Python-2, тоді як xrange
у Python-3 вони не виконали
Щасливе кодування !!
Це з міркувань оптимізації.
range () створить список значень від початку до кінця (0 .. 20 у вашому прикладі). Це стане дорогою операцією на дуже великих діапазонах.
xrange (), з іншого боку, значно оптимізованіший. він буде обчислювати наступне значення лише при необхідності (через об'єкт послідовності xrange) і не створюватиме список усіх значень, таких як range ().
range(x,y)
повертає список кожного числа між x і y, якщо ви використовуєте for
цикл, то range
це повільніше. Фактично, range
має більший діапазон індексів. range(x.y)
надрукує список усіх чисел між x і y
xrange(x,y)
повертається, xrange(x,y)
але якщо ви використовували for
цикл, то xrange
це швидше. xrange
має менший діапазон індексів. xrange
не тільки роздрукується, xrange(x,y)
але й збереже всі номери, що знаходяться в ньому.
[In] range(1,10)
[Out] [1, 2, 3, 4, 5, 6, 7, 8, 9]
[In] xrange(1,10)
[Out] xrange(1,10)
Якщо ви використовуєте for
цикл, то він би спрацював
[In] for i in range(1,10):
print i
[Out] 1
2
3
4
5
6
7
8
9
[In] for i in xrange(1,10):
print i
[Out] 1
2
3
4
5
6
7
8
9
Існує не велика різниця при використанні циклів, хоча є різниця, коли просто друкуємо його!
range (): діапазон (1, 10) повертає список від 1 до 10 чисел і зберігає весь список у пам'яті.
xrange (): як діапазон (), але замість повернення списку повертає об'єкт, який генерує числа в діапазоні на вимогу. Для циклічного циклу це трохи швидше, ніж діапазон () та більш ефективна пам'ять. xrange () об'єкт, як ітератор, і генерує числа за запитом. (Lazy Evaluation)
In [1]: range(1,10)
Out[1]: [1, 2, 3, 4, 5, 6, 7, 8, 9]
In [2]: xrange(10)
Out[2]: xrange(10)
In [3]: print xrange.__doc__
xrange([start,] stop[, step]) -> xrange object
Деякі з інших відповідей зазначити , що Python 3 усунутий 2.x - х range
і перейменований 2.x років xrange
в range
. Однак, якщо ви не використовуєте 3.0 або 3.1 (чого ніхто не повинен бути), це насправді дещо інший тип.
Як кажуть 3.1 документа :
Об'єкти діапазону мають дуже мало поведінки: вони підтримують лише індексацію, ітерацію та
len
функцію.
Однак у 3.2+ range
- це повна послідовність - вона підтримує розширені фрагменти та всі методи collections.abc.Sequence
з тією ж семантикою, що й a list
. *
І, принаймні, у CPython та PyPy (єдині дві впроваджені на сьогоднішній день 3.2+), він також має реалізацію index
та count
методи і in
оператор ( до тих пір , як ви тільки передати його цілі числа). Це означає, що писати 123456 in r
розумно в 3.2+, тоді як в 2.7 або 3.1 це буде жахливою ідеєю.
* Те, що issubclass(xrange, collections.Sequence)
повертається True
в 2.6-2.7 та 3.0-3.1 - це помилка яка була виправлена в 3.2 та не підтримувалася.
У пітоні 2.х
range (x) повертає список, створений в пам'яті з елементами x.
>>> a = range(5)
>>> a
[0, 1, 2, 3, 4]
xrange (x) повертає об'єкт xrange, який є генератором obj, який генерує числа за запитом. вони обчислюються під час циклу for-loop (Ледача оцінка).
Для циклічного циклу це трохи швидше, ніж діапазон () та більш ефективна пам'ять.
>>> b = xrange(5)
>>> b
xrange(5)
xrange()
не генератор. xrange(n)
.__ iter __ () `є.
Під час тестування діапазону проти xrange в циклі (я знаю, що я повинен використовувати timeit , але це було швидко вирвано з пам'яті за допомогою простого прикладу розуміння списку), я виявив наступне:
import time
for x in range(1, 10):
t = time.time()
[v*10 for v in range(1, 10000)]
print "range: %.4f" % ((time.time()-t)*100)
t = time.time()
[v*10 for v in xrange(1, 10000)]
print "xrange: %.4f" % ((time.time()-t)*100)
що дає:
$python range_tests.py
range: 0.4273
xrange: 0.3733
range: 0.3881
xrange: 0.3507
range: 0.3712
xrange: 0.3565
range: 0.4031
xrange: 0.3558
range: 0.3714
xrange: 0.3520
range: 0.3834
xrange: 0.3546
range: 0.3717
xrange: 0.3511
range: 0.3745
xrange: 0.3523
range: 0.3858
xrange: 0.3997 <- garbage collection?
Або, використовуючи xrange у циклі for:
range: 0.4172
xrange: 0.3701
range: 0.3840
xrange: 0.3547
range: 0.3830
xrange: 0.3862 <- garbage collection?
range: 0.4019
xrange: 0.3532
range: 0.3738
xrange: 0.3726
range: 0.3762
xrange: 0.3533
range: 0.3710
xrange: 0.3509
range: 0.3738
xrange: 0.3512
range: 0.3703
xrange: 0.3509
Чи правильно перевіряється мій фрагмент? Будь-які коментарі до повільнішого екземпляра xrange? Або кращий приклад :-)
xrange
здавався трохи швидшим, хоча з Python 3 порівняння зараз є зайвим.
timeit
. Він піклується про те, щоб працювати багато разів, відключати GC, використовувати найкращий годинник замість time
тощо.
xrange () і range () в python працює аналогічно, як і для користувача, але різниця виникає, коли ми говоримо про те, як розподіляється пам'ять у використанні обох функцій.
Коли ми використовуємо range (), ми виділяємо пам’ять на всі змінні, які вона генерує, тому не рекомендується використовувати з більшими ні. змінних, які потрібно генерувати.
xrange (), з іншого боку, генерує лише певне значення одночасно і може використовуватися лише для циклу for для друку всіх необхідних значень.
Що?
range
повертає статичний список під час виконання.
xrange
повертаєobject
(який діє як генератор, хоча він, звичайно, не один), з якого формуються значення як і коли потрібно.
Коли використовувати який?
xrange
якщо ви хочете створити список для гігантського діапазону, скажімо, 1 мільярд, особливо коли у вас є "чутлива до пам'яті система", як мобільний телефон.range
якщо ви хочете повторити список кілька разів.PS: Python 3.x в range
функції == Python 2.x в xrange
функції.
xrange
не повертає об'єкт генератора.
Всі це чудово пояснили. Але я хотів, щоб це побачив сам. Я використовую python3. Отже, я відкрив монітор ресурсів (у Windows!), І спочатку виконав таку команду:
a=0
for i in range(1,100000):
a=a+i
а потім перевірити зміни в пам'яті "In Use". Це було незначно. Потім я запустив такий код:
for i in list(range(1,100000)):
a=a+i
І це миттєво зайняло великий шматок пам'яті. І, я переконався. Ви можете спробувати на собі.
Якщо ви використовуєте Python 2X, замініть 'range ()' на 'xrange ()' у першому коді, а 'list (range ())' на 'range ()'.
З довідкових док.
Пітон 2.7.12
>>> print range.__doc__
range(stop) -> list of integers
range(start, stop[, step]) -> list of integers
Return a list containing an arithmetic progression of integers.
range(i, j) returns [i, i+1, i+2, ..., j-1]; start (!) defaults to 0.
When step is given, it specifies the increment (or decrement).
For example, range(4) returns [0, 1, 2, 3]. The end point is omitted!
These are exactly the valid indices for a list of 4 elements.
>>> print xrange.__doc__
xrange(stop) -> xrange object
xrange(start, stop[, step]) -> xrange object
Like range(), but instead of returning a list, returns an object that
generates the numbers in the range on demand. For looping, this is
slightly faster than range() and more memory efficient.
Пітон 3.5.2
>>> print(range.__doc__)
range(stop) -> range object
range(start, stop[, step]) -> range object
Return an object that produces a sequence of integers from start (inclusive)
to stop (exclusive) by step. range(i, j) produces i, i+1, i+2, ..., j-1.
start defaults to 0, and stop is omitted! range(4) produces 0, 1, 2, 3.
These are exactly the valid indices for a list of 4 elements.
When step is given, it specifies the increment (or decrement).
>>> print(xrange.__doc__)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'xrange' is not defined
Різниця очевидна. У Python 2.x range
повертає список, xrange
повертає об'єкт xrange, який є ітерабельним.
У Python 3.x, range
стає xrange
Python 2.x, і xrange
видаляється.
Щодо вимоги сканування / друку 0-N елементів, діапазон і xrange працює наступним чином.
range () - створює новий список у пам'яті та займає цілі 0 до N елементів (повністю N + 1) та друкує їх. xrange () - створює ітераторський екземпляр, який сканує елементи та зберігає в пам’яті лише поточний зустрічається елемент, отже, весь час використовує однаковий об’єм пам’яті.
Якщо потрібний елемент дещо знаходиться на початку списку, лише тоді він економить багато часу та пам'яті.
xrange
не створює ітератор. Він створює xrange
об'єкт, який є ітерабельним, але не є ітератором - майже (але не зовсім) послідовністю, як список.
Діапазон повертає список, тоді як xrange повертає об’єкт xrange, який займає ту саму пам'ять, незалежно від розміру діапазону, як у цьому випадку, генерується лише один елемент та доступний за ітерацію, тоді як у разі використання діапазону всі елементи генеруються одразу та доступні в пам'яті.
Різниця зменшується для менших аргументів до range(..)
/ xrange(..)
:
$ python -m timeit "for i in xrange(10111):" " for k in range(100):" " pass"
10 loops, best of 3: 59.4 msec per loop
$ python -m timeit "for i in xrange(10111):" " for k in xrange(100):" " pass"
10 loops, best of 3: 46.9 msec per loop
У цьому випадку xrange(100)
це лише приблизно на 20% ефективніше.
діапазон: -range буде заповнювати все одразу. Що означає, що кожне число діапазону займе пам'ять.
xrange: -range є чимось на зразок генератора, він з'явиться на малюнку, коли ви хочете, щоб діапазон чисел, але ви не хочете, щоб вони зберігалися, як, коли ви хочете використовувати в loop.so ефективної пам'яті.
Крім того, якщо робити, list(xrange(...))
це буде еквівалентноrange(...)
.
Тому list
повільно.
Також xrange
дійсно не повністю закінчується послідовність
Тож тому його не список, а xrange
об’єкт
range()
в Python 2.x
Ця функція по суті є старою range()
функцією, яка була доступна в Python 2.x
і повертає екземпляр alist
об'єкта, який містить елементи у вказаному діапазоні.
Однак ця реалізація є занадто неефективною, коли мова йде про ініціалізацію списку з діапазоном чисел. Наприклад, for i in range(1000000)
було б дуже дорогою командою для виконання, як з точки зору пам'яті, так і часу, оскільки це вимагає зберігання цього списку в пам'яті.
range()
в Python 3.x
і xrange()
в Python2.x
Python 3.x
представив нову реалізацію range()
(тоді як новіша реалізація вже була доступна в Python 2.x
черезxrange()
функцію).
range()
Використовує стратегію , відому як лінива оцінку. Замість того, щоб створити величезний список елементів у діапазоні, новіша реалізація представляє клас range
, легкий об’єкт, який представляє необхідні елементи у заданому діапазоні, не зберігаючи їх явно в пам'яті (це може звучати як генератори, але концепція ледачої оцінки - це інший).
Як приклад розглянемо наступне:
# Python 2.x
>>> a = range(10)
>>> type(a)
<type 'list'>
>>> b = xrange(10)
>>> type(b)
<type 'xrange'>
і
# Python 3.x
>>> a = range(10)
>>> type(a)
<class 'range'>
Дивіться цю публікацію щоб знайти різницю між діапазоном і xrange:
Цитувати:
range
повертає саме те, що ви думаєте: список послідовних цілих чисел, визначеної довжини, що починається з 0.xrange
, однак повертає "xrange об'єкт" , який діє дуже як ітератор
xrange
не є ітератором. Список, що повертається, range
підтримує ітерацію (список - це майже прототипний приклад ітерабельності). Загальна вигода від xrange
"не мінімальна". І так далі.