반복자 변수없이 Python for range 루프를 구현할 수 있습니까?


187

없이 다음을 수행 할 수 i있습니까?

for i in range(some_number):
    # do something

N 번 무언가를하고 반복자가 필요없는 경우.


21
이것은 좋은 질문입니다! PyDev는 심지어 'i'를 '사용하지 않은 변수'에 대한 경고로 표시합니다. 아래의 해결책은이 경고를 제거합니다.
Ashwin Nanjappa

@Ashwin \ @UnusedVariable을 사용하여 해당 경고를 제거 할 수 있습니다. 이 주석을 통과 시키려면 'at'기호를 이스케이프해야했습니다.
Raffi Khatchadourian

나는 당신에게 같은 질문을합니다. pylint 경고로 성가시다. 물론 @Raffi Khatchadourian과 같은 추가 억제를 통해 경고를 비활성화 할 수 있습니다. Pylint 경고 억제 설명 을 피하는 것이 좋습니다 .
탱고

답변:


110

내 머리 꼭대기에서

나는 당신이 할 수있는 최선의 방법은 다음과 같다고 생각합니다.

def loop(f,n):
    for i in xrange(n): f()

loop(lambda: <insert expression here>, 5)

그러나 나는 당신이 여분의 i변수로 살 수 있다고 생각합니다 .

다음은 _실제로 다른 변수 인 변수 를 사용하는 옵션 입니다.

for _ in range(n):
    do_something()

참고 _대화 형 파이썬 세션에서 반환 된 마지막 결과를 할당 :

>>> 1+2
3
>>> _
3

이런 이유로 나는 이런 식으로 사용하지 않을 것입니다. Ryan이 언급 한 바와 같이 어떤 관용구도 알지 못합니다. 통역사가 엉망이 될 수 있습니다.

>>> for _ in xrange(10): pass
...
>>> _
9
>>> 1+2
3
>>> _
9

Python grammar 에 따르면 허용되는 변수 이름입니다.

identifier ::= (letter|"_") (letter | digit | "_")*

4
"하지만 난 당신이 여분의"i "와 함께 살 수 있다고 생각합니다. 그래, 그것은 단지 학문적 포인트입니다.
James McMahon

1
@nemo, 영숫자 이름을 사용하지 않으려면 range (n)에서 _을 시도하십시오.
알 수없는

이 경우 _는 변수입니까? 아니면 파이썬에서 다른 것이 있습니까?
James McMahon

1
@nemo 예, 허용되는 변수 이름입니다. 인터프리터에서는 마지막으로 작성한 표현식이 자동으로 할당됩니다.
알 수없는

3
@kurczak 포인트가 있습니다. 를 사용 _하면 무시해야한다는 것이 분명해집니다. 이 작업에 아무런 의미가 없다고 말하는 것은 코드를 주석 처리 할 때 아무런 의미가 없다고 말하는 것과 같습니다. 왜냐하면 어쨌든 정확히 동일하기 때문입니다.
Lambda Fairy

69

당신은 찾고 있습니다

for _ in itertools.repeat(None, times): ...

이것은 times파이썬에서 시간 을 반복하는 가장 빠른 방법 입니다.


2
나는 성능에 관심이 없었으며, 성명서를 작성하는 더 터무니없는 방법이 있는지 궁금했습니다. 나는 약 2 년 동안 산발적으로 파이썬을 사용했지만 여전히 누락 된 것이 많이 있다고 느낍니다. Itertools는 그러한 것들 중 하나입니다. 정보에 감사드립니다.
James McMahon

5
흥미 롭습니다. 방금 itertools 문서를 살펴 보았습니다. 하지만 왜 range 또는 xrange를 사용하는 것보다 이것이 더 빠른지 궁금합니다.
si28719e

5
@blackkettle : xrange 비용의 측정 가능한 부분 인 현재 반복 인덱스를 반환 할 필요가 없기 때문에 더 빠릅니다 (파이썬 3의 범위는 목록이 아닌 반복자를 제공합니다). @nemo, 범위는 가능한 한 최적화되었지만 목록을 작성하고 반환 해야하는 것은 반복기보다 필연적으로 무거운 작업입니다 (Py3에서 범위는 Py2의 xrange와 같이 반복기를 반환합니다. 역 호환성은 그러한 변경을 허용하지 않습니다) Py2에서), 특히 다양한 값을 반환 할 필요가없는 것.
Alex Martelli

4
@Cristian, 예, 매번 Python int를 명확하게 준비하고 반환합니다. gc 작업, 측정 비용이 들지만 내부 에서 카운터를 사용하는 것은 중요하지 않습니다.
Alex Martelli

4
지금은 이해. 차이점은 "알고리즘"이 아니라 GC 오버 헤드에서 비롯됩니다. 그건 그렇고, 빠른 timeit 벤치 마크를 실행 했으며 속도는 ~ 1.42x였습니다.
Cristian Ciupitu

59

사용되지 않는 값에 할당하는 일반적인 관용구는 이름을 지정하는 것 _입니다.

for _ in range(times):
    do_stuff()

18

_ 사용을 제안하는 모든 사람들이 말하는 것은 아닙니다. _는 gettext 함수 중 하나에 대한 바로 가기로 자주 사용 되므로 소프트웨어를 여러 언어로 사용할 수있게하려면 사용하지 않는 것이 좋습니다. 다른 목적으로.

import gettext
gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')
gettext.textdomain('myapplication')
_ = gettext.gettext
# ...
print _('This is a translatable string.')

나 에게이 사용은 _끔찍한 생각처럼 보이고, 나는 그것을 상충하지 않을 것입니다.
KeithWM

9

다음은 데이터 모델 ( Py3 link ) 을 활용하는 임의의 아이디어입니다 .

class Counter(object):
    def __init__(self, val):
        self.val = val

    def __nonzero__(self):
        self.val -= 1
        return self.val >= 0
    __bool__ = __nonzero__  # Alias to Py3 name to make code work unchanged on Py2 and Py3

x = Counter(5)
while x:
    # Do something
    pass

표준 라이브러리에 이와 같은 것이 있는지 궁금합니다.


10
__nonzero__부작용과 같은 방법을 사용하는 것이 끔찍한 생각이라고 생각합니다.
ThiefMaster

2
__call__대신에 사용하겠습니다 . while x():작성하기가 그리 어렵지 않습니다.
Jasmijn

1
이름을 피하기위한 주장도 있습니다 Counter. 확실히, 그것은 예약되거나 내장 된 범위에 있지 않지만 collections.Counter사물 이며 같은 이름의 클래스를 만들면 관리자가 혼란에 빠질 수 있습니다 (이것은 이미 위험하지 않습니다).
ShadowRanger

7

_11 (또는 임의의 숫자 또는 다른 잘못된 식별자)을 사용하여 gettext와의 이름 충돌을 방지 할 수 있습니다. 밑줄 + 잘못된 식별자를 사용할 때마다 for 루프에서 사용할 수있는 더미 이름이 나타납니다.


좋은! PyDev는 귀하에게 동의합니다. "사용하지 않는 변수"노란색 경고가 사라집니다.
마이크 설치류

2

반복자를 사용하는 데 어떤 문제가 있는지에 대한 답이 될 수 있습니까? 사용되었을지도 모른다

i = 100
while i:
    print i
    i-=1

또는

def loop(N, doSomething):
    if not N:
        return
    print doSomething(N)
    loop(N-1, doSomething)

loop(100, lambda a:a)

그러나 솔직히 나는 그러한 접근법을 사용하는 데 아무런 의미가 없습니다.


1
참고 : Python (최소한 CPython 참조 인터프리터는 아니지만 적어도 대부분은 그렇지 않을 수도 있음)은 꼬리 재귀를 최적화하지 않으므로 N은 값의 근처에있는 것으로 제한됩니다 sys.getrecursionlimit()(기본값은 하위 4의 어딘가에 있습니다) CPython의 숫자 범위); 를 사용 sys.setrecursionlimit하면 한계가 높아지지만 결국 C 스택 한계에 도달하면 인터프리터는 스택 오버플로로 죽을 것입니다 (좋은 RuntimeError/를 올리는 것뿐만 아니라 RecursionError).
ShadowRanger


1

불필요한 카운터 대신 이제 불필요한 목록이 있습니다. 가장 좋은 해결책은 "_"로 시작하는 변수를 사용하는 것입니다.이 변수는 구문 검사기에게 변수를 사용하고 있지 않다는 것을 알려줍니다.

x = range(5)
while x:
  x.pop()
  print "Work!"

0

나는 일반적으로 위에 주어진 해결책에 동의합니다. 즉 :

  1. for-loop 에서 밑줄 사용 (2 줄 이상)
  2. 일반 while카운터 정의 (3 줄 이상)
  3. __nonzero__구현 으로 커스텀 클래스 선언 하기 (많은 줄)

하나 같이 객체를 정의하는 경우 # 3 난에 대한 프로토콜을 구현하는 것이 좋습니다 키워드 또는 적용 contextlib을 .

또한 나는 또 다른 해결책을 제안합니다. 3 라이너이며 최고의 우아함은 아니지만 itertools 패키지를 사용하므로 관심이있을 수 있습니다.

from itertools import (chain, repeat)

times = chain(repeat(True, 2), repeat(False))
while next(times):
    print 'do stuff!'

이 예에서 2 는 루프를 반복하는 횟수입니다. chain 은 두 개의 반복 반복자를 감싸고 있으며 첫 번째는 제한적이지만 두 번째는 무한합니다. 이들은 진정한 반복자 객체이므로 무한 메모리가 필요하지 않습니다. 분명히 이것은 솔루션 # 1 보다 훨씬 느립니다 . 함수의 일부로 작성되지 않는 한 시간 동안 변수 정리가 필요할 수 있습니다 .


2
chain불필요 times = repeat(True, 2); while next(times, False):하고 같은 일을합니다.
AChampion

0

우리는 다음과 같이 재미있었습니다.

class RepeatFunction:
    def __init__(self,n=1): self.n = n
    def __call__(self,Func):
        for i in xrange(self.n):
            Func()
        return Func


#----usage
k = 0

@RepeatFunction(7)                       #decorator for repeating function
def Job():
    global k
    print k
    k += 1

print '---------'
Job()

결과 :

0
1
2
3
4
5
6
---------
7

0

경우 do_something간단한 기능 또는 하나의 간단한에 싸여 할 수 map()do_something range(some_number)시간 :

# Py2 version - map is eager, so it can be used alone
map(do_something, xrange(some_number))

# Py3 version - map is lazy, so it must be consumed to do the work at all;
# wrapping in list() would be equivalent to Py2, but if you don't use the return
# value, it's wastefully creating a temporary, possibly huge, list of junk.
# collections.deque with maxlen 0 can efficiently run a generator to exhaustion without
# storing any of the results; the itertools consume recipe uses it for that purpose.
from collections import deque

deque(map(do_something, range(some_number)), 0)

에 인수를 전달 do_something하려면 itertools repeatfunc레시피 가 잘 읽힐 수도 있습니다 .

동일한 인수를 전달하려면 다음을 수행하십시오.

from collections import deque
from itertools import repeat, starmap

args = (..., my args here, ...)

# Same as Py3 map above, you must consume starmap (it's a lazy generator, even on Py2)
deque(starmap(do_something, repeat(args, some_number)), 0)

다른 인수를 전달하려면 다음을 수행하십시오.

argses = [(1, 2), (3, 4), ...]

deque(starmap(do_something, argses), 0)

-1

당신이 경우 정말 이름으로 뭔가를 넣어 (반복의 영업과 같이 변수 또는 원치 않는 목록 또는 시간의 진정한 원하는 금액을 반환 원치 않는 발전기 중 하나) 당신이 정말 원한다면 당신이 그것을 할 수 않도록하려면 :

for type('', (), {}).x in range(somenumber):
    dosomething()

사용되는 트릭은 type('', (), {})빈 이름의 클래스 를 생성하는 익명 클래스를 작성하는 것이지만 NB는 로컬 또는 글로벌 네임 스페이스에 삽입되지 않습니다 (빈 이름이 제공되지 않은 경우에도). 그런 다음 해당 클래스의 멤버를 멤버로 사용하는 클래스에 도달 할 수 없으므로이 클래스의 멤버를 반복 변수로 사용하십시오.


분명히 이것은 의도적으로 병리학 적이므로 비판하는 것은 요점 옆에 있지만 여기에 추가 함정이 있습니다. 참조 인터프리터 인 CPython에서 클래스 정의는 기본적으로 주기적입니다 (클래스를 작성하면 참조 계산에 따라 클래스의 결정적 정리를 방해하는 참조주기가 불가피하게 발생 함). 그것은 당신이 수업을 시작하고 정리하기 위해 주기적 GC를 기다리고 있음을 의미합니다. 일반적으로 젊은 세대의 일부로 수집되며 기본적으로 자주 수집되지만 각 루프는 비 결정적 수명을 가진 ~ 1.5KB의 가비지를 의미합니다.
ShadowRanger

기본적으로 각 루프에서 (일반적으로) 결정적으로 정리되는 명명 된 변수를 피하기 위해 (반환되고 오래된 값이 정리 될 때), 비 결정적으로 청소되고 쉽게 할 수있는 거대한 명명되지 않은 변수를 만들고 있습니다 오래갑니다.
ShadowRanger


-7

이건 어떤가요:

while range(some_number):
    #do something

3
조건 range(some_number)이 항상 참이므로 무한 루프 입니다!
치명적인

@deadly : 글쎄, some_number이보다 작거나 같으면 0무한하지 않고 결코 실행되지 않습니다. 그것은 신선한 작성하기 :-) 그리고, (특히 Py2에) 무한 루프 오히려 비효율적이다 list(Py2) 또는 range각 시험 객체 (Py3)을 (그것이 부하가,보기의 통역의 관점에서 일정한 아니다 rangesome_number모든 루프를 호출 range하고 결과를 테스트하십시오).
ShadowRanger
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.