Odpowiedzi:
W Python 2.x:
range
tworzy listę, więc jeśli to zrobisz range(1, 10000000)
, tworzy listę w pamięci z 9999999
elementami.
xrange
jest obiektem sekwencji, który ocenia leniwie.
W Pythonie 3 range
robi odpowiednik Pythona xrange
i aby uzyskać listę, musisz użyć list(range(...))
.
xrange(x).__iter__()
jest generatorem.
i
jest oceniany na żądanie, a nie podczas inicjalizacji.
zakres tworzy listę, więc jeśli to zrobisz
range(1, 10000000)
, tworzy listę w pamięci z9999999
elementami.
xrange
Jest to generator, więcjest obiektem sekwencjito, że ocenia się leniwie.
To prawda, ale w Pythonie 3 .range()
zostanie zaimplementowane przez Python 2 .xrange()
. Jeśli musisz wygenerować listę, musisz:
list(range(1,100))
xrange
generatora? Jest to funkcja zawierająca yield
instrukcję i zgodnie ze słownikiem funkcje takie nazywane są generatorami.
Pamiętaj, użyj timeit
modułu do przetestowania, który z małych fragmentów kodu jest szybszy!
$ 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
Osobiście zawsze używam .range()
, chyba że mam do czynienia z naprawdę dużymi listami - jak widać pod względem czasowym, dla listy milionów wpisów, dodatkowy narzut wynosi tylko 0,04 sekundy. I, jak zauważa Corey, w Pythonie 3.0 .xrange()
odejdzie i .range()
da ci ładne zachowanie iteratora.
python -m timeit "for i in xrange(1000000):" " pass"
the extra overhead is only 0.04 seconds
nie jest to właściwy sposób patrzenia na to, (90.5-51.1)/51.1 = 1.771 times slower
jest poprawna, ponieważ przekazuje, że jeśli jest to główna pętla twojego programu, może to potencjalnie wąskie gardło. Jeśli jednak jest to niewielka część, 1,77x to niewiele.
xrange
przechowuje tylko parametry zakresu i generuje liczby na żądanie. Jednak implementacja języka C w Pythonie obecnie ogranicza swoje argumenty do długości C:
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]
Zauważ, że w Pythonie 3.0 jest tylko range
i zachowuje się jak 2.x, xrange
ale bez ograniczeń minimalnych i maksymalnych punktów końcowych.
xrange zwraca iterator i zachowuje tylko jedną liczbę w pamięci na raz. zakres zachowuje całą listę liczb w pamięci.
xrange
nie nie zwraca iterator.
and only keeps one number in memory at a time
a gdzie reszta jest umieszczona, proszę poprowadź mnie ..
Spędź trochę czasu z Library Reference . Im bardziej go znasz, tym szybciej znajdziesz odpowiedzi na takie pytania. Szczególnie ważne jest kilka pierwszych rozdziałów na temat wbudowanych obiektów i typów.
Zaletą typu Xrange jest to, że obiekt Xrange zawsze zajmuje tę samą ilość pamięci, bez względu na rozmiar reprezentowanego przez niego zakresu. Nie ma stałych korzyści w zakresie wydajności.
Innym sposobem na znalezienie szybkiej informacji o konstrukcji Pythona jest docstring i funkcja pomocy:
print xrange.__doc__ # def doc(x): print x.__doc__ is super useful
help(xrange)
Jestem zszokowany, nikt nie czytał dokumentu :
Ta funkcja jest bardzo podobna do
range()
, ale zwracaxrange
obiekt zamiast listy. Jest to nieprzezroczysty typ sekwencji, który daje takie same wartości jak odpowiadająca mu lista, bez faktycznego przechowywania ich wszystkich jednocześnie. Przewagaxrange()
overrange()
jest minimalna (ponieważxrange()
wciąż trzeba tworzyć wartości, gdy zostanie o to poproszony), z wyjątkiem sytuacji, gdy na maszynie pozbawionej pamięci używany jest bardzo duży zakres lub gdy wszystkie elementy zakresu nie są nigdy używane (na przykład gdy pętla jest zwykle zakończonebreak
).
zakres tworzy listę, więc jeśli wykonasz zakres (1, 10000000), tworzona jest lista pamięci zawierająca 10000000 elementów. xrange jest generatorem, więc ocenia leniwie.
Daje to dwie zalety:
MemoryError
.Zaletę xrange
ponad znajdziesz range
w tym prostym przykładzie:
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
Powyższy przykład nie odzwierciedla niczego znacznie lepszego w przypadku xrange
.
Teraz spójrz na następujący przypadek, w którym range
jest naprawdę bardzo wolny, w porównaniu do 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
Za pomocą range
tworzy już listę od 0 do 100000000 (czasochłonną), ale xrange
jest generatorem i generuje liczby tylko na podstawie potrzeby, to znaczy, jeśli iteracja będzie kontynuowana.
W Pythonie-3 implementacja range
funkcjonalności jest taka sama jak xrange
w Pythonie-2, podczas gdy zlikwidowano xrange
w Pythonie-3
Happy Coding !!
To z powodów optymalizacji.
range () utworzy listę wartości od początku do końca (w twoim przykładzie 0 .. 20). To stanie się kosztowną operacją na bardzo dużych zasięgach.
Z drugiej strony xrange () jest znacznie bardziej zoptymalizowany. oblicza następną wartość tylko w razie potrzeby (za pomocą obiektu sekwencji Xrange) i nie tworzy listy wszystkich wartości, jak robi to zakres ().
range(x,y)
zwraca listę każdej liczby pomiędzy xiy, jeśli używasz for
pętli, wtedy range
jest wolniejsza. W rzeczywistości range
ma większy zakres indeksu. range(x.y)
wypisze listę wszystkich liczb pomiędzy xiy
xrange(x,y)
zwraca, xrange(x,y)
ale jeśli użyłeś for
pętli, to xrange
jest szybszy. xrange
ma mniejszy zakres indeksu. xrange
nie tylko wydrukuje, xrange(x,y)
ale zachowa wszystkie zawarte w nim liczby.
[In] range(1,10)
[Out] [1, 2, 3, 4, 5, 6, 7, 8, 9]
[In] xrange(1,10)
[Out] xrange(1,10)
Jeśli użyjesz for
pętli, to zadziała
[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
Nie ma dużej różnicy przy korzystaniu z pętli, choć jest różnica tylko podczas drukowania!
range (): range (1, 10) zwraca listę od 1 do 10 liczb i utrzymuje całą listę w pamięci.
xrange (): Podobnie jak range (), ale zamiast zwracać listę, zwraca obiekt, który na żądanie generuje liczby w zakresie. W przypadku zapętlania jest to nieco szybsze niż range () i bardziej wydajna pamięć. Obiekt xrange () jak iterator i generuje liczby na żądanie. (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
Niektóre inne odpowiedzi wspominają, że Python 3 wyeliminował 2.x range
i zmienił nazwę 2.x xrange
na range
. Jednakże, chyba że używasz wersji 3.0 lub 3.1 (którymi nikt nie powinien być), to w rzeczywistości jest to nieco inny typ.
Jak mówią dokumenty 3.1 :
Obiekty zakresu mają bardzo małe zachowanie: obsługują tylko indeksowanie, iterację i
len
funkcję.
Jednak w wersji 3.2+ range
jest to pełna sekwencja - obsługuje rozszerzone wycinki i wszystkie metody collections.abc.Sequence
z tą samą semantyką jak list
. *
I, przynajmniej w CPython i pypy (jedyne dwa 3.2 lub nowszym wdrożeń, które obecnie istnieją), ma też implementacje stałej porze index
i count
metod oraz in
operatora (tak długo, jak tylko go przekazywać liczby całkowite). Oznacza to, że pisanie 123456 in r
jest rozsądne w wersji 3.2+, podczas gdy w wersji 2.7 lub 3.1 byłby to okropny pomysł.
* Fakt, że issubclass(xrange, collections.Sequence)
powraca True
w wersjach 2.6-2.7 i 3.0-3.1, jest błędem, który został naprawiony w wersji 3.2 i nie został przeniesiony.
W python 2.x
zakres (x) zwraca listę utworzoną w pamięci za pomocą x elementów.
>>> a = range(5)
>>> a
[0, 1, 2, 3, 4]
xrange (x) zwraca obiekt xrange, który jest generatorem obj, który generuje liczby na żądanie. są obliczane podczas pętli for (Lazy Evaluation).
W przypadku zapętlania jest to nieco szybsze niż zakres () i bardziej wydajna pamięć.
>>> b = xrange(5)
>>> b
xrange(5)
xrange()
nie jest generatorem. xrange(n)
.__ iter __ () `is.
Podczas testowania zasięgu względem xrange w pętli (wiem, że powinienem użyć timeit , ale szybko zhackowałem go z pamięci za pomocą prostego przykładu ze zrozumieniem listy) znalazłem:
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)
co daje:
$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?
Lub używając xrange w pętli 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
Czy testowanie mojego fragmentu jest prawidłowe? Jakieś komentarze na temat wolniejszej instancji Xrange? Lub lepszy przykład :-)
xrange
wydawałem się nieco szybszy, chociaż w Pythonie 3 porównanie jest teraz zbędne.
timeit
jest. Zajmuje się bieganiem wiele razy, wyłączaniem GC, używaniem najlepszego zegara zamiast time
itp.
xrange () i range () w pythonie działają podobnie jak dla użytkownika, ale różnica pojawia się, gdy mówimy o tym, jak pamięć jest przydzielana przy użyciu obu funkcji.
Kiedy używamy range (), przydzielamy pamięć dla wszystkich generowanych zmiennych, więc nie zaleca się używania z większym nie. zmiennych do wygenerowania.
Z drugiej strony xrange () generuje tylko określoną wartość na raz i może być używana tylko z pętlą for do drukowania wszystkich wymaganych wartości.
zakres generuje całą listę i zwraca ją. xrange nie - generuje na żądanie liczby z listy.
Co?
range
zwraca statyczną listę w czasie wykonywania.
xrange
zwraca object
(który działa jak generator, choć na pewno nie jest to jeden), z którego wartości są generowane w razie potrzeby.
Kiedy stosować który?
xrange
jeśli chcesz wygenerować listę dla gigantycznego zasięgu, powiedzmy 1 miliard, zwłaszcza gdy masz „system wrażliwy na pamięć”, taki jak telefon komórkowy.range
jeśli chcesz kilkakrotnie iterować listę.PS: Python 3.x jest range
funkcja == Python 2.x jest xrange
funkcja.
xrange
nie zwraca obiektu generatora.
Wszyscy to doskonale wyjaśnili. Ale chciałem to zobaczyć na własne oczy. Używam python3. Otworzyłem więc monitor zasobów (w systemie Windows!) I najpierw wykonałem następujące polecenie:
a=0
for i in range(1,100000):
a=a+i
a następnie sprawdził zmianę w pamięci „W użyciu”. To było nieistotne. Następnie uruchomiłem następujący kod:
for i in list(range(1,100000)):
a=a+i
Natychmiast zajęło to sporo pamięci. I byłem przekonany. Możesz spróbować sam.
Jeśli używasz Python 2X, zamień „range ()” na „xrange ()” w pierwszym kodzie, a „list (range ())” na „range ()”.
Z dokumentacji pomocy.
Python 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.
Python 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
Różnica jest widoczna. W Pythonie 2.x range
zwraca listę, xrange
zwraca obiekt xrange, który jest iterowalny.
W Python 3.x range
staje się xrange
Python 2.x i xrange
jest usuwany.
W przypadku wymagań dotyczących skanowania / drukowania elementów 0-N zakres i zakres X działają w następujący sposób.
range () - tworzy nową listę w pamięci i przenosi całe 0 do N elementów (całkowicie N + 1) i drukuje je. xrange () - tworzy instancję iteratora, która skanuje elementy i przechowuje tylko bieżący napotkany element w pamięci, a zatem wykorzystuje tę samą ilość pamięci przez cały czas.
W przypadku, gdy wymagany element znajduje się nieco na początku listy, oszczędza to sporo czasu i pamięci.
xrange
nie tworzy instancji iteratora. Tworzy xrange
obiekt, który jest iterowalny, ale nie jest iteratorem - prawie (ale nie do końca) sekwencją, jak lista.
Range zwraca listę, podczas gdy xrange zwraca obiekt xrange, który zajmuje tę samą pamięć niezależnie od wielkości zakresu, ponieważ w tym przypadku generowany jest tylko jeden element i dostępny na iterację, natomiast w przypadku użycia zakresu wszystkie elementy są generowane jednocześnie i są dostępne w pamięci.
Różnica maleje w przypadku mniejszych argumentów do 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
W tym przypadku xrange(100)
jest tylko około 20% bardziej wydajny.
zakres: -zakres zapełni wszystko naraz. co oznacza, że każda liczba zakresu zajmie pamięć.
xrange: -xrange jest czymś w rodzaju generatora, pojawi się na obrazie, gdy chcesz zakres liczb, ale nie chcesz, aby były przechowywane, na przykład gdy chcesz użyć pętli. tak wydajna pamięć.
Dodatkowo, jeśli do list(xrange(...))
będzie równoważne range(...)
.
Więc list
jest wolny.
Również xrange
naprawdę nie w pełni kończy sekwencję
Dlatego to nie jest lista, to xrange
obiekt
range()
w Pythonie 2.x
Ta funkcja jest zasadniczo starą range()
funkcją dostępną w Pythonie 2.x
i zwraca instancję list
obiektu zawierającego elementy z określonego zakresu.
Jednak ta implementacja jest zbyt nieefektywna, jeśli chodzi o inicjalizację listy z zakresem liczb. Na przykład for i in range(1000000)
wykonanie polecenia byłoby bardzo kosztowne, zarówno pod względem zużycia pamięci, jak i czasu, ponieważ wymaga przechowywania tej listy w pamięci.
range()
w Python 3.x
i xrange()
Python2.x
Python 3.x
wprowadził nowszą implementację range()
(podczas gdy nowsza implementacja była już dostępna w Pythonie 2.x
za pośrednictwemxrange()
funkcję).
range()
Wykorzystuje strategię zwaną oceny leniwy. Zamiast tworzyć ogromną listę elementów w zakresie, nowsza implementacja wprowadza klasę range
, lekki obiekt, który reprezentuje wymagane elementy w danym zakresie, bez przechowywania ich wyraźnie w pamięci (może to brzmieć jak generatory, ale koncepcja leniwej oceny jest różne).
Jako przykład weź pod uwagę następujące kwestie:
# Python 2.x
>>> a = range(10)
>>> type(a)
<type 'list'>
>>> b = xrange(10)
>>> type(b)
<type 'xrange'>
i
# Python 3.x
>>> a = range(10)
>>> type(a)
<class 'range'>
Zobacz ten post aby znaleźć różnicę między zasięgiem a zasięgiem xrange:
Cytować:
range
zwraca dokładnie to, co myślisz: listę kolejnych liczb całkowitych o określonej długości rozpoczynającej się od 0.xrange
zwraca jednak „obiekt xrange” , który działa bardzo podobnie jak iterator
xrange
nie jest iteratorem. Lista zwracana przez range
nie obsługuje iteracji (lista jest w zasadzie prototypowym przykładem iterowalności). Ogólna korzyść xrange
nie jest „minimalna”. I tak dalej.