Programing

기본 파이썬 반복기 빌드

lottogame 2020. 2. 10. 22:03
반응형

기본 파이썬 반복기 빌드


파이썬에서 반복 함수 (또는 반복자 객체)를 어떻게 만들 수 있습니까?


반복자는 파이썬의 객체는 기본적으로 그들은 두 가지 방법을 제공하는 것을 의미 반복자 프로토콜을 준수 : __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 는 꽤 좋은 소개입니다.


반복 함수를 작성하는 네 가지 방법이 있습니다.

예 :

# 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_genuc_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



반응형