파이썬에서 반복 함수 (또는 반복자 객체)를 어떻게 만들 수 있습니까?
답변
반복자는 파이썬의 객체는 기본적으로 그들은 두 가지 방법을 제공하는 것을 의미 반복자 프로토콜을 준수 : __iter__()
와 __next__()
.
-
이
__iter__
반복자 객체를 반환하며 루프 시작시 암시 적으로 호출됩니다. -
이
__next__()
메소드는 다음 값을 리턴하며 각 루프 증분마다 내재적으로 호출됩니다. 이 메소드는 리턴 할 값이 더 이상 없을 때 StopIteration 예외를 발생시킵니다. 이는 반복을 중지하기 위해 루프 구문을 통해 암시 적으로 캡처됩니다.
다음은 간단한 카운터 예입니다.
class Counter:
def __init__(self, low, high):
self.current = low - 1
self.high = high
def __iter__(self):
return self
def __next__(self): # Python 2: def next(self)
self.current += 1
if self.current < self.high:
return self.current
raise StopIteration
for c in Counter(3, 9):
print(c)
인쇄됩니다 :
3
4
5
6
7
8
이전 답변에서 다룬 것처럼 생성기를 사용하여 작성하는 것이 더 쉽습니다.
def counter(low, high):
current = low
while current < high:
yield current
current += 1
for c in counter(3, 9):
print(c)
인쇄 된 출력물이 동일합니다. 후드에서 생성기 객체는 반복기 프로토콜을 지원하고 클래스 클래스와 거의 비슷한 작업을 수행합니다.
David Mertz의 기사 인 Iterators와 Simple Generators 는 꽤 좋은 소개입니다.
답변
반복 함수를 작성하는 네 가지 방법이 있습니다.
- 생성기 생성 ( yield 키워드 사용 )
- 생성기 표현식 사용 ( genexp )
- 반복자를 만듭니다 (defines
__iter__
및__next__
(또는next
Python 2.x)) - 파이썬이 스스로 반복 할 수있는 클래스를 만듭니다 ( define
__getitem__
)
예 :
# generator
def uc_gen(text):
for char in text.upper():
yield char
# generator expression
def uc_genexp(text):
return (char for char in text.upper())
# iterator protocol
class uc_iter():
def __init__(self, text):
self.text = text.upper()
self.index = 0
def __iter__(self):
return self
def __next__(self):
try:
result = self.text[self.index]
except IndexError:
raise StopIteration
self.index += 1
return result
# getitem method
class uc_getitem():
def __init__(self, text):
self.text = text.upper()
def __getitem__(self, index):
return self.text[index]
네 가지 방법을 모두 보려면 :
for iterator in uc_gen, uc_genexp, uc_iter, uc_getitem:
for ch in iterator('abcde'):
print(ch, end=' ')
print()
결과 :
A B C D E
A B C D E
A B C D E
A B C D E
참고 :
두 발전기 유형 ( uc_gen
및 uc_genexp
)은 reversed()
; 평범한 반복자 ( uc_iter
)는 __reversed__
마술 방법 이 필요합니다 ( docs에 따르면 새로운 반복자를 반환하지만 self
작업을 반환해야 합니다 (적어도 CPython에서)). 그리고 getitem iteratable ( uc_getitem
)에는 __len__
마술 방법 이 있어야합니다 .
# for uc_iter we add __reversed__ and update __next__
def __reversed__(self):
self.index = -1
return self
def __next__(self):
try:
result = self.text[self.index]
except IndexError:
raise StopIteration
self.index += -1 if self.index < 0 else +1
return result
# for uc_getitem
def __len__(self)
return len(self.text)
무한 게으르게 평가 된 반복자에 대한 Panic 대령의 두 번째 질문에 대답하기 위해 위의 네 가지 방법 각각을 사용하는 예제가 있습니다.
# generator
def even_gen():
result = 0
while True:
yield result
result += 2
# generator expression
def even_genexp():
return (num for num in even_gen()) # or even_iter or even_getitem
# not much value under these circumstances
# iterator protocol
class even_iter():
def __init__(self):
self.value = 0
def __iter__(self):
return self
def __next__(self):
next_value = self.value
self.value += 2
return next_value
# getitem method
class even_getitem():
def __getitem__(self, index):
return index * 2
import random
for iterator in even_gen, even_genexp, even_iter, even_getitem:
limit = random.randint(15, 30)
count = 0
for even in iterator():
print even,
count += 1
if count >= limit:
break
print
결과는 (적어도 내 샘플 실행의 경우) :
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32
사용할 것을 선택하는 방법? 이것은 대부분 맛의 문제입니다. 내가 가장 자주 보는 두 가지 방법은 생성기 및 반복기 프로토콜뿐만 아니라 하이브리드 ( __iter__
생성기 반환)입니다.
생성기 표현식은 목록 이해를 대체하는 데 유용합니다 (게 으르므로 리소스를 절약 할 수 있음).
이전 Python 2.x 버전과의 호환성이 필요한 경우을 사용하십시오 __getitem__
.
답변
우선 itertools 모듈 은 반복자가 유용한 모든 종류의 경우에 매우 유용하지만 파이썬에서 반복자를 작성하는 데 필요한 모든 것입니다.
수율
멋지지 않습니까? 수익률은 함수 의 정규 수익 을 대체하는 데 사용할 수 있습니다 . 객체를 동일하게 반환하지만 상태를 파괴하고 종료하는 대신 다음 반복을 실행할 때의 상태를 저장합니다. itertools 함수 목록 에서 직접 가져온 조치의 예는 다음과 같습니다 .
def count(n=0):
while True:
yield n
n += 1
함수 설명 ( itertools 모듈 의 count () 함수입니다 …)에 명시된 것처럼 n으로 시작하는 연속 정수를 반환하는 반복자를 생성합니다.
생성기 표현 은 다른 웜 캔 (굉장한 웜)입니다. 그것들은 메모리를 절약하기 위해 List Comprehension 대신에 사용될 수 있습니다 (list comprehension은 변수에 할당되지 않은 경우 사용 후 파괴 된 메모리에 목록을 생성하지만 제너레이터 표현식은 Generator Object를 생성 할 수 있습니다 … 반복자). 다음은 생성기 표현식 정의의 예입니다.
gen = (n for n in xrange(0,11))
이것은 전체 범위가 0에서 10 사이로 미리 결정된 것을 제외하고는 위의 반복자 정의와 매우 유사합니다.
방금 xrange () (이전에는 보지 못했지만 …)를 발견하고 위의 예제에 추가했습니다. xrange () 는 리스트를 미리 빌드하지 않는 이점이있는 range () 의 반복 가능한 버전입니다 . 반복 할 거대한 데이터 모음이 있고 메모리가 너무 많으면 매우 유용합니다.
답변
나는 당신이 어떤 일을 볼 수 return self
에서 __iter__
. 난 그냥 참고로 원 __iter__
자체가 (따라서에 대한 필요성을 제거하는 발전기가 될 수 __next__
및 양육 StopIteration
예외)
class range:
def __init__(self,a,b):
self.a = a
self.b = b
def __iter__(self):
i = self.a
while i < self.b:
yield i
i+=1
물론 여기서 직접 생성기를 만들 수도 있지만 더 복잡한 클래스의 경우 유용 할 수 있습니다.
답변
이 질문은 반복자가 아닌 반복 가능한 객체에 관한 것입니다. 파이썬에서 시퀀스는 반복 가능하므로 반복 가능한 클래스를 만드는 한 가지 방법은 시퀀스와 같은 동작, 즉 메소드 __getitem__
와 __len__
메소드를 제공하는 것 입니다. 파이썬 2와 3에서 이것을 테스트했습니다.
class CustomRange:
def __init__(self, low, high):
self.low = low
self.high = high
def __getitem__(self, item):
if item >= len(self):
raise IndexError("CustomRange index out of range")
return self.low + item
def __len__(self):
return self.high - self.low
cr = CustomRange(0, 10)
for i in cr:
print(i)
답변
이 페이지의 모든 답변은 복잡한 개체에 정말 좋습니다. 그러나 속성으로 반복 가능한 종류의 내장 포함 된 사람들을 위해, 같은 str
, list
, set
또는 dict
, 또는의 구현 collections.Iterable
, 당신은 당신의 수업 시간에 어떤 일을 생략 할 수 있습니다.
class Test(object):
def __init__(self, string):
self.string = string
def __iter__(self):
# since your string is already iterable
return (ch for ch in self.string)
# or simply
return self.string.__iter__()
# also
return iter(self.string)
다음과 같이 사용할 수 있습니다.
for x in Test("abcde"):
print(x)
# prints
# a
# b
# c
# d
# e
답변
이없는 반복 가능한 함수 yield
입니다. 그것은 사용할 수 있도록 iter
기능과 변경 가능한 (에서의 상태를 유지하는 폐쇄 list
파이썬 2의 둘러싸 범위를).
def count(low, high):
counter = [0]
def tmp():
val = low + counter[0]
if val < high:
counter[0] += 1
return val
return None
return iter(tmp, None)
Python 3의 경우 클로저 상태는 둘러싸는 범위에서 변경할 수 없으며 nonlocal
로컬 변수에서 상태 변수를 업데이트하는 데 사용됩니다.
def count(low, high):
counter = 0
def tmp():
nonlocal counter
val = low + counter
if val < high:
counter += 1
return val
return None
return iter(tmp, None)
테스트;
for i in count(1,10):
print(i)
1
2
3
4
5
6
7
8
9