Відповіді:
У 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стає xrangePython 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"не мінімальна". І так далі.