인덱스 변수없이 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.