인덱스 변수없이 N 번 무언가를하는 pythonic 방법?


161

매일 저는 점점 더 파이썬을 좋아합니다.

오늘은 다음과 같은 코드를 작성했습니다.

for i in xrange(N):
    do_something()

나는 N 번 무언가를해야했습니다. 그러나 매번 i(인덱스 변수) 의 값에 의존하지 않았습니다 . 나는 내가 결코 사용하지 않은 변수를 만들고 있다는 것을 깨달았고 ( i") 쓸모없는 색인 변수가 필요 없이이 작업을 수행하는 더 파이썬적인 방법이 있다고 생각했습니다.

그래서 ... 질문은 :이 간단한 작업을 좀 더 (파이썬) 아름다운 방법으로 수행하는 방법을 알고 있습니까?


7
방금 _ 변수에 대해 배웠지 만 그렇지 않으면 파이썬 방식을 고려할 것입니다. 나는 적어도 파이썬에서 다른 방법으로 수행 된 간단한 for 루프를 본 적이 없다고 생각합니다. 비록 당신이 그것을보고 "잠깐, 그게 끔찍해 보인다"라고 말하는 특정 사용 사례가 있다고 확신하지만, 일반적으로 xrange가 선호되는 방법입니다 (내가 본 한).
Wayne Werner 2016 년


5
참고 : xrange는 Python3에 없습니다. range대신 사용하십시오 .
John Henckel

답변:


110

루핑보다 약간 빠른 접근 방식 xrange(N)은 다음과 같습니다.

import itertools

for _ in itertools.repeat(None, N):
    do_something()

3
얼마나 빨리? 파이썬 3.1에는 여전히 차이점이 있습니까?
Hamish Grubijan

15
@Hamish : 2.6으로 테스트 한 결과 32 % 빠릅니다 (N = 1000의 경우 23.2 us vs 17.6 us). 그러나 그것은 어쨌든 정말 시간입니다. OP의 코드는 더 즉시 읽을 수 있기 때문에 기본값으로 사용합니다.
Mike Boers 2018 년

3
속도에 대해 아는 것이 좋습니다. 나는 OP의 코드가 더 읽기 쉽다는 것에 대한 Mike의 감정을 분명히 반향한다.
Wayne Werner

@Wayne, 나는 습관이 매우 강력하다고 생각합니다. 여러분이 익숙해 졌다는 사실을 제외하고는 왜이 카운트를 수행 할 때마다 "0에서 N-1까지 (그리고 카운트를 완전히 무시)" -독립적 인 조작 "은 본질적으로"다음 번의 N 번 반복 조작 "보다 명확합니까?
Alex Martelli 2016 년

4
속도가 실제로 관련되어 있습니까? 루프에서 중요한 작업을 수행하는 경우 선택한 반복 스타일보다 수백 또는 수천 시간이 걸릴 것입니까?
Henning

55

질문을 할 때 배운 _ 변수를 사용하십시오 ( 예 :

# A long way to do integer exponentiation
num = 2
power = 3
product = 1
for _ in xrange(power):
    product *= num
print product

6
downvoter는 아니지만 답변에 더 자세한 내용을 추가하는 대신 다른 게시물을 참조하기 때문일 수 있습니다.
Downgoat

5
@ Downgoat : 피드백 감사합니다. 즉,이 관용구에 대해서는 그렇게 말할 것이 없습니다. 다른 게시물을 언급 할 때의 요점은 검색이 답을 얻었을 수 있음을 지적하는 것이 었습니다. 나는이 질문이 다른 질문보다 몇 배나 많은 공언을 가지고 있다는 것이 아이러니하다는 것을 안다.
GreenMatt


10

함수는 일류 시민이기 때문에 작은 래퍼를 작성할 수 있습니다 (Alex 답변에서)

def repeat(f, N):
    for _ in itertools.repeat(None, N): f()

그런 다음 함수를 인수로 전달할 수 있습니다.


@Hamish : 거의 아무것도 없습니다. (Alex의 답변 타이밍과 동일한 조건에서 루프 당 17.8 us, 0.2 us 차이).
Mike Boers 2018 년

9

_는 x와 같습니다. 그러나 사용하지 않을 식별자를 나타내는 데 사용되는 파이썬 관용구입니다. 파이썬에서 이러한 식별자는 변수가 다른 언어 에서처럼 기억하거나 공간을 할당하지 않습니다. 잊어 버리기 쉽습니다. 그것들은 객체를 가리키는 이름 일뿐입니다.이 경우 각 반복에서 정수입니다.


8

다양한 답변이 정말 우아하다는 것을 알았지 만 (특히 Alex Martelli의) 성능을 직접 측정하고 싶었으므로 다음 스크립트를 작성했습니다.

from itertools import repeat
N = 10000000

def payload(a):
    pass

def standard(N):
    for x in range(N):
        payload(None)

def underscore(N):
    for _ in range(N):
        payload(None)

def loopiter(N):
    for _ in repeat(None, N):
        payload(None)

def loopiter2(N):
    for _ in map(payload, repeat(None, N)):
        pass

if __name__ == '__main__':
    import timeit
    print("standard: ",timeit.timeit("standard({})".format(N),
        setup="from __main__ import standard", number=1))
    print("underscore: ",timeit.timeit("underscore({})".format(N),
        setup="from __main__ import underscore", number=1))
    print("loopiter: ",timeit.timeit("loopiter({})".format(N),
        setup="from __main__ import loopiter", number=1))
    print("loopiter2: ",timeit.timeit("loopiter2({})".format(N),
        setup="from __main__ import loopiter2", number=1))

또한 Martelli의 솔루션을 기반으로 map()하고 페이로드 함수를 호출하는 데 사용되는 대체 솔루션을 생각해 냈습니다 . OK, 나는 페이로드가 버려지는 매개 변수를 받아 들일 수있는 자유를 얻었습니다.이 주위에 방법이 있는지 모르겠습니다. 그럼에도 불구하고 결과는 다음과 같습니다.

standard:  0.8398549720004667
underscore:  0.8413165839992871
loopiter:  0.7110594899968419
loopiter2:  0.5891903560004721

따라서 map을 사용하면 표준 for 루프보다 약 30 %, Martelli보다 19 % 더 향상됩니다.


4

do_something 을 함수로 정의 하고 N 번 수행 한다고 가정합니다 . 아마도 다음을 시도해 볼 수 있습니다.

todos = [do_something] * N  
for doit in todos:  
    doit()

45
확실한. 함수를 백만 번 호출하는 것이 아니라 백만 개의 항목 목록도 할당 해 봅시다. CPU가 작동하면 메모리도 약간 스트레스를받지 않아야합니까? 답은 "유용하지 않다"(특별하고 기능적인 접근 방식을 보여주고 있음)라고 특징 지을 수 없으므로 공감할 수는 없지만 동의하지 않으며 전적으로 반대합니다.
tzot

1
동일한 함수 값에 대한 N 참조 목록이 아닌가요?
Nick McCurdy

fn() for fn in itertools.repeat(do_something, N)배열을 미리 생성하고 저장 하는 것이 더 좋습니다 ... 이것은 내가 선호하는 관용구입니다.
F1Rumors

1
@tzot 왜 상쾌한 톤입니까? 이 사람은 답을 쓰려고 노력하고 있으며 이제는 미래에 기여하지 않는 것이 좋습니다. 성능에 영향을 미치더라도 작동 옵션이며 특히 N이 작 으면 성능 / 메모리 의미는 중요하지 않습니다.
davidscolgan

나는 파이썬 개발자가 성능에 집착하는 방식에 항상 놀랐습니다. : 관용적이지 않다는 것에 동의하지만 파이썬을 처음 접하는 사람은 단순히 반복자를 사용할 때만 큼 명확하게 이해하지 못할 수도 있습니다.
Asfand Qazi

1

간단한 while 루프는 어떻습니까?

while times > 0:
    do_something()
    times -= 1

이미 변수가 있습니다. 왜 사용하지 않습니까?


1
나의 유일한 생각은 그것이 3 줄의 코드 대 하나 (?)라는 것이다.
AJP

2
@AJP-4 줄 대 2 줄
ArtOfWarfare

오버 헤드에 비교 (times> 0) 및 감소 (
times-

@ F1Rumors 그것을 측정하지는 않았지만 PyPy와 같은 JIT 컴파일러가 간단한 while 루프에 대해 느린 코드를 생성 해야하는지 놀랐습니다.
Philipp Claßen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.