Python3에 xrange 함수가없는 이유는 무엇입니까?


273

최근에 Python3을 사용하기 시작했으며 xrange 상처가 부족합니다.

간단한 예 :

1) 파이썬 2 :

from time import time as t
def count():
  st = t()
  [x for x in xrange(10000000) if x%4 == 0]
  et = t()
  print et-st
count()

2) 파이썬 3 :

from time import time as t

def xrange(x):

    return iter(range(x))

def count():
    st = t()
    [x for x in xrange(10000000) if x%4 == 0]
    et = t()
    print (et-st)
count()

결과는 각각 다음과 같습니다.

1) 1.53888392448 2) 3.215819835662842

왜 그런 겁니까? 왜 xrange가 제거 되었습니까? 배우기에 훌륭한 도구입니다. 우리 모두가 어느 시점에 있었던 것처럼, 나처럼 초보자도. 왜 제거해야합니까? 누군가가 올바른 PEP를 알려줄 수 있습니까? 찾을 수 없습니다.

건배.


231
rangePython 3.x는 xrangePython 2.x에서 가져온 것입니다. 실제로 파이썬 2.x range가 제거되었습니다.
Anorov

27
추신, 당신은 결코 시간과 함께해서는 안됩니다 time. 사용하기 쉽고 잘못하기가 더 어려워지고 테스트를 반복하는 것 외에도 timeit기억하지 못하거나 모든 방법을 알고 (GC를 사용하지 않도록 설정하는 것과 같이) 돌보는 방법을 알고, 수천 배 더 나은 해상도로 시계.
abarnert

7
또한, 왜 당신은 필터링하는 시간 테스트 range에를 x%4 == 0? 왜 테스트 list(xrange())list(range())합니까? 가능한 한 외부 작업이 적습니까? (예를 들어, 3.x가 x%4더 느리게 수행되지 않는다는 것을 어떻게 알 수 있습니까?) 그 문제에 대해 왜 list많은 메모리 할당을 포함하는 거대한을 구축하고 있습니까 (느린 것 외에도 놀랍도록 가변적입니다) ?
abarnert

5
docs.python.org/3.0/whatsnew/3.0.html , "목록 대신보기 및 반복자"섹션을 참조하십시오 . "range ()는 이제 임의의 크기 값으로 작동하는 것을 제외하고는 작동하는 데 사용 된 xrange ()처럼 작동합니다. 더 이상 존재하지 않다." 따라서 range는 이제 반복자를 반환합니다. iter(range)중복됩니다.
ToolmakerSteve

9
죄송합니다. 변경 문서를 인용한다고 맹목적으로 눈에 띄지는 않습니다. 혼란스럽고 오랫동안 받아 들여진 대답과 모든 주석을 읽고 싶지 않은 사람은 파이썬 2에서 xrange를 사용하는 곳마다 파이썬 3에서 range를 사용하십시오. xrange가했던 일을 수행합니다. 반복자를 돌려줍니다. 목록에 결과가 필요한 경우을 수행하십시오 list(range(..)). 그것은 파이썬 2의 범위와 같습니다. 또는 다른 말로하면 : xrange는 더 나은 기본값이기 때문에 range로 이름이 바뀌 었습니다. 둘 다 가질 필요는 없었습니다 list(range). 정말로 목록이 필요한 경우 수행 하십시오. .
ToolmakerSteve

답변:


175

일부 성능 측정은, 사용 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 비트 :

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. 그리고 OP의 xrange기능은 그것과 관련이 없습니다. ( __iter__슬롯 에 대한 일회성 호출 이 루프에서 발생하는 모든 작업에 대해 10000000 번의 호출 중 보이지 않을 가능성이 있지만 누군가가이를 가능성으로 제기 한 것은 놀라운 일 이 아닙니다.)

그러나 30 % 더 느립니다. 영업 이익은 어떻게 2 배나 느려졌습니까? 글쎄, 32 비트 파이썬으로 동일한 테스트를 반복하면 1.58 대 3.12를 얻습니다. 그래서 이것은 32 비트를 손상시키는 방식으로 3.x가 64 비트 성능에 맞게 최적화 된 경우 중 하나입니다.

하지만 정말 중요합니까? 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전체 반복보다 두 배 이상의 시간이 소요됩니다.

그리고 "파이썬 2.6+보다 훨씬 더 많은 리소스를 소비한다"는 테스트에서 3.x range는 2.x xrange와 정확히 같은 크기 인 것 같습니다. 범위 반복이 할 수있는 것보다 여전히 약 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사람들이 같은 것을 몇 번이나 말했는지에 관계없이 왜 제거 되었는지 묻는 질문을 반복하지만 다시 반복하겠습니다. 제거되지 않았습니다. 이름이로 바뀌었고 range2.x range가 제거되었습니다.

다음은 3.3 range객체가 2.x xrange객체가 아닌 2.x 객체 의 직접적인 자손 이라는 증거입니다 range. 소스는 3.3range2.7xrange 입니다. 당신은 심지어 변경 내역을 볼 수 있습니다 (파일의 어느 곳에서나 문자열 "xrange"의 마지막 인스턴스를 대체 한 변경 사항에 연결되어 있다고 생각합니다).

왜 느린가요?

글쎄, 그들은 많은 새로운 기능을 추가했습니다. 다른 경우에는 사소한 부작용이있는 모든 장소 (특히 반복 내부)에서 모든 종류의 변경을 수행했습니다. 때로는 덜 중요한 경우를 약간 비관 화하더라도 다양한 중요한 경우를 극적으로 최적화하기위한 많은 작업이있었습니다. 이 모든 것을 합하면 가능한 range한 빨리 반복하는 것이 조금 느리다는 사실에 놀라지 않습니다 . 아무도 그다지 집중하지 않을 정도로 덜 중요한 경우 중 하나입니다. 이 성능 차이가 코드의 핫스팟 인 실제 사용 사례는 없을 것입니다.


그러나 30 % 더 느립니다. 여전히 느리지 만 반응이 좋은 친구, 생각해야 할 것. 그래도 내 질문에 대답하지 않습니다. 왜 xrange가 제거 되었습니까? 한 번에 소비해야하는 대기열의 양을 아는 멀티 프로세싱 기반의 성능 종속 앱이 있다면 30 %가 차이를 만들지 않겠습니까? 알다시피, 당신은 그것이 중요하지 않다고 말하지만, 범위를 사용할 때마다 cpu가 최악이라는 것을 의미하는 거대한 고민 팬 소리가 들리지만 xrange는 그렇지 않습니다. 그것에 대해 생각;)
catalesia

9
@catalesia : 다시 한 번 제거되지 않고 이름이 변경되었습니다 range. range3.3 목적은 직접적인 자손 xrange하지의 2.7에서 객체 range2.7 함수. 님 itertools.imap을 찬성하여 삭제 하는 동안 질문하는 것과 같습니다 map. 그런 일이 없었기 때문에 답이 없습니다.
abarnert

1
@ catalesia : 사소한 성능 변화는 아마도 범위를 느리게 만들기위한 직접적인 디자인 결정의 결과가 아니라 많은 것들을 더 빠르게 만든 파이썬에서 4 년 동안의 변화로 인한 부작용으로 인해 약간의 속도가 느려집니다. x86_64에서는 더 빠르지 만 x86에서는 느리거나 일부 사용 사례에서는 더 빠르지 만 다른 경우에는 더 느립니다.) 아무도 다른 range일을하지 않고 반복하는 데 걸리는 시간이 30 % 차이에 대해 걱정하지 않았을 것입니다.
abarnert

1
"아무 것도하지 않고 범위를 반복하는 데 걸리는 시간이 30 % 차이에 대해 걱정할 사람이 아무도 없었습니다. "
catalesia

18
@ catalesia : 그렇습니다. 그러나 당신은 그것이 말하는 것과 반대되는 것을 의미한다고 생각하는 것 같습니다. 누구나 관심을 가질 유스 케이스가 아니므로 30 % 느려진 사람은 없습니다. 그래서 무엇? 이 때문에 2.7 (또는 2.6)보다 Python 3.3에서 더 느리게 실행되는 실제 프로그램을 찾을 수 있다면 사람들은 신경 쓸 것입니다. 당신이 할 수 없다면, 그들은하지 않을 것입니다.
abarnert

141

Python3의 범위 Python2의 xrange입니다. 주위에 iter를 감쌀 필요가 없습니다. Python3에서 실제 목록을 얻으려면list(range(...))

Python2 및 Python3에서 작동하는 것을 원한다면 이것을 시도하십시오

try:
    xrange
except NameError:
    xrange = range

1
때로는 파이썬 2와 3 모두에서 작동하는 코드가 필요합니다. 이것은 좋은 솔루션입니다.
Greg Glockner

3
문제는 이것으로 둘 다를 사용 range하고 xrange다르게 행동 하는 코드입니다 . 이 작업을 수행하는 것만으로는 충분하지 않습니다 range. 파이썬 2에서와 같이 목록을 반환 한다고 가정해서는 안됩니다 .
LangeHaare

이 프로젝트에서 xrange를 사용할 수 있습니다. 이 futurize: 자동으로 당신에게 소스 코드를 변환하는 도구 python-future.org/...
guettli

17

Python 3의 range유형은 Python 2와 동일하게 작동합니다 xrange. xrange함수에서 반환 된 반복자 가 range직접 반복하면 얻을 수있는 것이기 때문에 왜 느려지는 지 잘 모르겠습니다 .

시스템 속도 저하를 재현 할 수 없습니다. 내가 테스트 한 방법은 다음과 같습니다.

파이썬 2 xrange:

Python 2.7.3 (default, Apr 10 2012, 23:24:47) [MSC v.1500 64 bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> import timeit
>>> timeit.timeit("[x for x in xrange(1000000) if x%4]",number=100)
18.631936646865853

Python 3 range은 조금 더 빠릅니다.

Python 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:57:17) [MSC v.1600 64 bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> import timeit
>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100)
17.31399508687869

내가 최근 파이썬 3의 사실을 알게 range유형은 슬라이스에 대한 지원과 같은 다른 깔끔한 기능을 가지고 range(10,100,2)[5:25:5]있다 range(20, 60, 10)!


아마도 속도 저하는 xrange여러 번의 새로운 조회에서 비롯된 것일까 요, 아니면 한 번만 수행 되었습니까?
askewchan

어쨌든 반복자가 실제로 속도를 증가 시킵니까? 방금 메모리를 절약했다고 ​​생각했습니다.
askewchan

3
@catalesia 여기 요점은 그 생각 xrange하고 있지 , 제거 단지 이름 .
askewchan

1
@Blckknght : 건배, 그러나 여전히 다음과 같은 설명이 필요합니다. "리터럴과 이해를 설정하십시오 [19] [20] [완료] {x}는 set ([x])을 의미합니다; {x, y}는 set ([ x, y]). {P (x)} 인 경우 S의 x에 대한 F (x)는 p (x) 인 경우 S의 x에 대한 F (x)를 의미합니다 .NB. {range (x)}는 set ( [range (x)]), NOT set (range (x)) 빈 세트에는 리터럴이 없으며 set () (또는 {1} & {2} :-)를 사용하십시오. 고정 된 리터럴 이 없습니다. 거의 필요하지 않습니다. "
catalesia의

3
range내가 아는 한 3.x에서 가장 큰 승리 는 상수 시간 __contains__입니다. 초보자는 글을 쓰고 300000 in xrange(1000000)그로 인해 전체 xrange(또는 적어도 첫 30 %) 를 반복하게 되었기 때문에 우리는 그것이 너무 비현실적으로 보이지만 왜 나쁜 생각인지 설명해야했습니다. 지금, 그것은 이다 파이썬.
abarnert

1

python2 코드를 수정하는 한 가지 방법은 다음과 같습니다.

import sys

if sys.version_info >= (3, 0):
    def xrange(*args, **kwargs):
        return iter(range(*args, **kwargs))

1
요점은 python3에 있습니다. xrange가 정의되어 있지 않으므로 xrange를 사용한 레거시 코드가 중단됩니다.
앤드류 페이트

아니오, 간단히 range = xrange
@John

@ mimi.vx xrange가 정의되지 않았기 때문에 range = xrange가 Python3에서 작동하는지 확실하지 않습니다. 내 의견은 xrange 호출이 포함 된 오래된 레거시 코드가 있고 python3에서 실행하려고하는 경우를 말합니다.
앤드류 페이트

1
아, 내 나쁜 .. xrange = range... 나는 성명을 전환
mimi.vx

range iiterator이며, 어쨌든 이것이 전체 범위의 포장을 풀고 이런 종류의 일에 iterator를 사용할 때의 이점을 잃어 버리기 때문에 그것이 끔찍한 아이디어 일 것입니다. 정확한 응답은 "range = xrange"가 아닙니다. "xrange = range"
Shayne

0

Python 2의 xrange는 생성기이며 iterator를 구현하는 반면 range는 단지 함수입니다. 파이썬 3에서는 왜 xrange에서 빠졌는지 모르겠습니다.


아니요, 범위는 인터 레이터가 아닙니다. 이 구조로는 next ()를 수행 할 수 없습니다. 자세한 정보를 원하시면, 여기에서 확인하실 수 있습니다 treyhunner.com/2018/02/python-range-is-not-an-iterator
미셸 페르난데스

설명해 주셔서 감사합니다. 그러나 원래 의견의 의도를 다시 말하겠습니다. 즉 PY3 range()은 PY2와 같습니다 xrange(). 따라서 PY3 xrange()에서는 중복됩니다.
Stephen Rauch

-2

comp : ~ $ python Python 2.7.6 (디폴트, 2015 년 6 월 22 일, 17:58:13) [linux2의 [GCC 4.8.2]

>>> import timeit
>>> timeit.timeit("[x for x in xrange(1000000) if x%4]",number=100)

5.656799077987671

>>> timeit.timeit("[x for x in xrange(1000000) if x%4]",number=100)

5.579368829727173

>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100)

21.54827117919922

>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100)

22.014557123184204

timeit 번호가 1 인 매개 변수 :

>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=1)

0.2245171070098877

>>> timeit.timeit("[x for x in xrange(1000000) if x%4]",number=1)

0.10750913619995117

comp : ~ $ python3 Python 3.4.3 (디폴트, 2015 년 10 월 14 일, 20:28:29) [GCC 4.8.4] Linux에서

>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100)

9.113872020003328

>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100)

9.07014398300089

timeit number = 1,2,3,4 매개 변수를 사용하면 빠르고 선형 적으로 작동합니다.

>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=1)

0.09329321900440846

>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=2)

0.18501482300052885

>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=3)

0.2703447980020428

>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=4)

0.36209142999723554

그래서 우리가 timeit.timeit ( "[x는 x는 x % 4]이면 x (1000000) x, x = x]], number = 1)과 같이 1 개의 실행 루프 사이클을 측정하면 python3은 충분히 빠르게 작동합니다. 그러나 반복 루프에서 파이썬 2 xrange ()는 파이썬 3의 range ()에 비해 속도가 빠릅니다.


그러나 이것은 언어 자체입니다 ... xrange / range와는 아무런 관련이 없습니다.
mimi.vx 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.