[python] 컨테이너 객체 (Python)에 대해 __iter __ (self)를 구현하는 방법

사용자 지정 컨테이너 개체를 작성했습니다.

이 페이지 에 따르면 내 개체에이 메서드를 구현해야합니다.

__iter__(self)

그러나 Python 참조 설명서의 반복자 유형 에 대한 링크를 따라 가면 직접 구현하는 방법에 대한 예제가 제공되지 않습니다.

누군가가이를 수행하는 방법을 보여주는 스 니펫 (또는 리소스에 대한 링크)을 게시 할 수 있습니까?

내가 쓰고있는 컨테이너는 맵 (즉, 고유 키로 값을 저장)입니다. dicts는 다음과 같이 반복 될 수 있습니다.

for k, v in mydict.items()

이 경우 반복기에서 두 개의 요소 (튜플?)를 반환 할 수 있어야합니다. (친절하게 제공된 여러 답변에도 불구하고) 그러한 반복자를 구현하는 방법은 아직 명확하지 않습니다. 누군가지도와 같은 컨테이너 객체에 대해 반복기를 구현하는 방법에 대해 좀 더 설명해 주시겠습니까? (예 : dict처럼 작동하는 사용자 정의 클래스)?



답변

나는 일반적으로 생성기 함수를 사용합니다. yield 문을 사용할 때마다 시퀀스에 항목이 추가됩니다.

다음은 5를 산출하는 반복자를 생성 한 다음 some_list의 모든 항목을 생성합니다.

def __iter__(self):
   yield 5
   yield from some_list

3.3 이전 버전 yield from은 존재하지 않았으므로 다음을 수행해야합니다.

def __iter__(self):
   yield 5
   for x in some_list:
      yield x


답변

또 다른 옵션은 여기에 설명 된대로`collections 모듈에서 적절한 추상 기본 클래스에서 상속하는 입니다.

컨테이너가 자체 반복자 인 경우
collections.Iterator. next그런 다음 메서드 를 구현하기 만하면됩니다.

예 :

>>> from collections import Iterator
>>> class MyContainer(Iterator):
...     def __init__(self, *data):
...         self.data = list(data)
...     def next(self):
...         if not self.data:
...             raise StopIteration
...         return self.data.pop()
...
...
...
>>> c = MyContainer(1, "two", 3, 4.0)
>>> for i in c:
...     print i
...
...
4.0
3
two
1

당신이보고있는 동안 collections모듈에서 상속 고려 Sequence, Mapping즉 더 적합한 지 또는 다른 추상 기본 클래스입니다. 다음은 Sequence하위 클래스 의 예입니다 .

>>> from collections import Sequence
>>> class MyContainer(Sequence):
...     def __init__(self, *data):
...         self.data = list(data)
...     def __getitem__(self, index):
...         return self.data[index]
...     def __len__(self):
...         return len(self.data)
...
...
...
>>> c = MyContainer(1, "two", 3, 4.0)
>>> for i in c:
...     print i
...
...
1
two
3
4.0

NB : 한편으로는 반복기와 다른 한편으로는 반복기보다는 반복 가능한 컨테이너 간의 차이점을 명확히해야한다는 점에주의를 기울여 주신 Glenn Maynard에게 감사드립니다.


답변

일반적으로 __iter__()next () 메서드 (generator 객체)를 이미 정의한 경우 self를 반환합니다.

다음은 생성기의 더미 예제입니다.

class Test(object):

    def __init__(self, data):
       self.data = data

    def next(self):
        if not self.data:
           raise StopIteration
        return self.data.pop()

    def __iter__(self):
        return self

다음 __iter__()과 같이 사용할 수도 있습니다 :
http://mail.python.org/pipermail/tutor/2006-January/044455.html


답변

개체에 개체의 iter를 바인딩하려는 데이터 집합이 포함 된 경우 속임수를 사용하여 다음을 수행 할 수 있습니다.

>>> class foo:
    def __init__(self, *params):
           self.data = params
    def __iter__(self):
        if hasattr(self.data[0], "__iter__"):
            return self.data[0].__iter__()
        return self.data.__iter__()
>>> d=foo(6,7,3,8, "ads", 6)
>>> for i in d:
    print i
6
7
3
8
ads
6


답변

파이썬의 “반복 가능한 인터페이스”는 두 가지 메서드 __next__()__iter__(). 이 __next__함수는 반복기 동작을 정의하므로 가장 중요합니다. 즉, 함수는 다음에 반환되어야하는 값을 결정합니다. 이 __iter__()메서드는 반복의 시작점을 재설정하는 데 사용됩니다. 종종 시작점을 설정하는 데 사용 __iter__()되면 self를 반환 할 수 있습니다 __init__().

“반복 가능한 인터페이스”를 구현하고 시퀀스 클래스의 모든 인스턴스에 대해 반복기를 정의하는 리버스 클래스를 정의하려면 다음 코드를 참조하십시오. 이 __next__()메서드는 시퀀스의 끝에서 시작하여 시퀀스의 역순으로 값을 반환합니다. “시퀀스 인터페이스”를 구현하는 클래스의 인스턴스는 __len__()__getitem__()메서드를 정의해야합니다 .

class Reverse:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, seq):
        self.data = seq
        self.index = len(seq)

    def __iter__(self):
        return self

    def __next__(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]

>>> rev = Reverse('spam')
>>> next(rev)   # note no need to call iter()
'm'
>>> nums = Reverse(range(1,10))
>>> next(nums)
9


답변

매핑에 대한 질문에 답하려면 제공된 사용자 가 매핑 __iter__반복해야 합니다. 다음은 매핑을 생성 하고 ABC 매핑을 확장하는 Python3에서 작동 하는 간단한 예제입니다 .x -> x * x

import collections.abc

class MyMap(collections.abc.Mapping):
    def __init__(self, n):
        self.n = n

    def __getitem__(self, key): # given a key, return it's value
        if 0 <= key < self.n:
            return key * key
        else:
            raise KeyError('Invalid key')

    def __iter__(self): # iterate over all keys
        for x in range(self.n):
            yield x

    def __len__(self):
        return self.n

m = MyMap(5)
for k, v in m.items():
    print(k, '->', v)
# 0 -> 0
# 1 -> 1
# 2 -> 4
# 3 -> 9
# 4 -> 16


답변

dict다른 사람들이 제안한 것처럼 상속하고 싶지 않은 경우 __iter__사용자 지정 사전의 원유 예제 를 구현하는 방법에 대한 질문에 대한 직접적인 답변이 있습니다 .

class Attribute:
    def __init__(self, key, value):
        self.key = key
        self.value = value

class Node(collections.Mapping):
    def __init__(self):
        self.type  = ""
        self.attrs = [] # List of Attributes

    def __iter__(self):
        for attr in self.attrs:
            yield attr.key

여기에 잘 설명 된 생성기를 사용합니다. .

에서 상속하므로 및 다음을 Mapping구현해야합니다 .__getitem____len__

    def __getitem__(self, key):
        for attr in self.attrs:
            if key == attr.key:
                return attr.value
        raise KeyError

    def __len__(self):
        return len(self.attrs)