기본 파이썬 반복기 빌드
파이썬에서 반복 함수 (또는 반복자 객체)를 어떻게 만들 수 있습니까?
반복자는 파이썬의 객체는 기본적으로 그들은 두 가지 방법을 제공하는 것을 의미 반복자 프로토콜을 준수 : __iter__()
와 __next__()
. 이 __iter__
반복자 객체를 반환하고 루프 시작시 암시 적으로 호출됩니다. 이 __next__()
메소드는 다음 값을 리턴하며 각 루프 증분마다 내재적으로 호출됩니다. __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:
yield char.upper()
# generator expression
def uc_genexp(text):
return (char.upper() for char in text)
# iterator protocol
class uc_iter():
def __init__(self, text):
self.text = text
self.index = 0
def __iter__(self):
return self
def __next__(self):
try:
result = self.text[self.index].upper()
except IndexError:
raise StopIteration
self.index += 1
return result
# getitem method
class uc_getitem():
def __init__(self, text):
self.text = text
def __getitem__(self, index):
result = self.text[index].upper()
return result
네 가지 방법을 모두 보려면 :
for iterator in uc_gen, uc_genexp, uc_iter, uc_getitem:
for ch in iterator('abcde'):
print ch,
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__
magic 메소드 (뒤로가는 새로운 반복자를 반환 해야 함)가 필요합니다 . 그리고 getitem iteratable ( uc_getitem
)은 __len__
마술 방법을 가져야합니다 :
# for uc_iter
def __reversed__(self):
return reversed(self.text)
# 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
짧고 간단한 것을 찾고 있다면 아마도 충분할 것입니다.
class A(object):
def __init__(self, l):
self.data = l
def __iter__(self):
return iter(self.data)
사용 예 :
In [3]: a = A([2,3,4])
In [4]: [i for i in a]
Out[4]: [2, 3, 4]
Matt Gregory의 대답에서 영감을 얻은 것은 a, b, ..., z, aa, ab, ..., zz, aaa, aab, ..., zzy, zzz를 반환하는 좀 더 복잡한 반복자입니다.
class AlphaCounter:
def __init__(self, low, high):
self.current = low
self.high = high
def __iter__(self):
return self
def __next__(self): # Python 3: def __next__(self)
alpha = ' abcdefghijklmnopqrstuvwxyz'
n_current = sum([(alpha.find(self.current[x])* 26**(len(self.current)-x-1)) for x in range(len(self.current))])
n_high = sum([(alpha.find(self.high[x])* 26**(len(self.high)-x-1)) for x in range(len(self.high))])
if n_current > n_high:
raise StopIteration
else:
increment = True
ret = ''
for x in self.current[::-1]:
if 'z' == x:
if increment:
ret += 'a'
else:
ret += 'z'
else:
if increment:
ret += alpha[alpha.find(x)+1]
increment = False
else:
ret += x
if increment:
ret += 'a'
tmp = self.current
self.current = ret[::-1]
return tmp
for c in AlphaCounter('a', 'zzz'):
print(c)
참고 URL : https://stackoverflow.com/questions/19151/build-a-basic-python-iterator
'Programing' 카테고리의 다른 글
JavaScript의 그래프 시각화 라이브러리 (0) | 2020.02.11 |
---|---|
GitHub에서 단일 파일 다운로드 (0) | 2020.02.10 |
Lollipop의 최신 Chrome 버전에서 헤더 바와 주소 표시 줄의 색상을 변경하는 방법은 무엇입니까? (0) | 2020.02.10 |
매개 변수가있는 RedirectToAction (0) | 2020.02.10 |
macOS Mojave (10.14)에서 Lion (10.7)의 JAVA_HOME은 어디에 있습니까? (0) | 2020.02.10 |