게시판

검색 결과: 8

, 도장_ 관리자님이 작성
 

1. Counter 클래스로 생성한 iterator는 range함수로 생성한 iterable과 같나요?
둘은 비슷하지만, 완전히 같지는 않습니다.
Counter 클래스로 생성한 객체는 인덱스로 값을 검색할 수 있으므로 __getitem__ 메서드를 사용하여 슬라이스를 지원합니다. 반면 range() 함수로 생성한 객체는 슬라이싱을 직접 지원하지 않습니다.

2. for문 iterable 자리에 Counter(3)이 있는데 Counter 클래스로 생성한 객체는 왜iterable이 아닌 iterator인가요? 제목은 '인덱스로 접근할 수 있는 이터레이터'인데 for문 iterable 자리에 Counter(3)이 있어서 궁금합니다.
Counter 클래스로 생성한 객체는 __getitem__ 메서드를 구현하고 있기 때문에 인덱스로 값에 접근할 수 있습니다. 그러나 __iter__를 구현하지 않았기 때문에 iter() 함수로 호출할 수 없습니다. 따라서 iterable 객체가 아니라 iterator입니다.

파이썬에서는 for 반복문에서 iterator 객체를 자동으로 iterable 객체로 변환합니다. for 반복문에서 Counter 클래스로 생성한 객체를 사용하면 __next__ 메서드를 호출해서 값을 하나씩 가져오면서 반복합니다.
Counter 클래스로 생성한 객체는 iterator이며, for 반복문에서 iterable 객체가 필요한 자리에 사용할 수 있습니다.

3. __getitem__ 메서드 안에 __iter__ 메서드와 __next__ 메서드가 구현(?)되어있나요?
__getitem__ 메서드 안에 __iter__와 __next__는 구현되어 있지 않습니다.

__getitem__ 메서드는 객체에 대한 인덱싱 연산을 처리하기 위한 매직 메서드입니다.

__iter__와 __next__ 메서드는 객체를 반복(iteration)할 수 있게 해주는 매직 메서드입니다.

__iter__ 메서드는 객체 자체를 반환하거나 새로운 iterator 객체를 반환하고, __next__ 메서드는 iterator 객체가 반환해야 할 다음 값을 반환하거나, StopIteration 예외를 발생시켜 반복을 종료합니다.

따라서, __getitem__ 메서드로 인덱싱 연산을 처리할 수 있지만, iterator로서의 기능을 수행하려면 __iter__ 메서드와 __next__ 메서드를 구현해야 합니다.



, 안 유진님이 작성
 

안녕하세요, 세가지 질문이 있습니다.

1. Counter 클래스로 생성한 iterator는 range함수로 생성한 iterable과 같나요?
2. for문 iterable 자리에 Counter(3)이 있는데 Counter 클래스로 생성한 객체는 왜iterable이 아닌 iterator인가요? 제목은 '인덱스로 접근할 수 있는 이터레이터'인데 for문 iterable 자리에 Counter(3)이 있어서 궁금합니다.
3. __getitem__ 메서드 안에 __iter__ 메서드와 __next__ 메서드가 구현(?)되어있나요?
=========================================================
class Counter:

def __init__(self, stop):

self.stop = stop


def __getitem__(self, index):

, 김 기업님이 작성
 

class TimeIterator:

    time = []

    

    def __init__(self, start, stop):        

        self.start = start

        self.stop = stop

        self.index = 0

        self.range = stop - start


    def __iter__(self):        

        return self

    

    def __next__(self):        

        start = self.start

        index = self.index

        self.start += 1

        self.index += 1

        hour = int(start // 3600)

        mod_hour = hour % 24

        minute = int((start - hour * 3600) // 60)

        second = int(start - hour * 3600 - minute * 60)

        time = '{0:>02d}:{1:>02d}:{2:>02d}'.format(mod_hour, minute, second)

        self.time.append(time)

        if self.start <= self.stop:

            return self.time[index]

        else:

            raise StopIteration

    

    def __getitem__(self, index):        

        if index < self.range:

            return self.time[index]

        else:

            raise IndexError


위의 코드로 심사 통과는 했는데요 __getitem__ 메서드 하나만으로는 구현이 안되는건가요? 위의 코드에서 __next__ 메서드를 없애고 시간 구하는 코드를 __getitem__ 으로 옮기면 TypeError: Iter() returned non-iterator of type 'TimeIterator' 에러가 발생 합니다. 왜 이런 에러가 발생하는 것인지요?

-------------------------------------------------------------------------------------

문제점 찾아서 수정했습니다. iter 메서드를 삭제하니 문제가 해결되었습니다. 39.3 내용 복습하면서 getitem을 사용하면 init 과 iter를 생략해도 된다라고 되어 있어서 삭제 해본 건데요, 생략해도 된다는 것과 반드시 삭제해야 하는 것은 좀 다른 의미라서 혹시 생략하지 않을 때에는 어떻게 써야만 위와 같은 에러가 안나는 건가요?

, 도장_ 관리자님이 작성
 

포럼 오른쪽 상단에 39.3으로 검색하면 이전 질문과 답변을 참조할 수 있습니다.

https://dojang.io/mod/forum/search.php?id=7&search=39.3


숫자와 리스트를 비교하는 게 아닙니다. my_list[0]처럼 리스트 안의 0번째 원소(아마도 숫자)와 숫자를 비교하는 것입니다.


, 최 승준님이 작성
 

class Counter:
    def __init__(self, stop):
        self.stop = stop
 
    def __getitem__(self, index):
        if index < self.stop:
            return index
        else:
            raise IndexError
 
print(Counter(3)[0], Counter(3)[1], Counter(3)[2])
 
for i in Counter(3):
    print(i, end=' ')

1. Counter 클래스는 숫자랑 리스트를 받아서 각각 stop이랑 index에 저장하는건가요?

2. __getitem__에서 index < self.stop 이라는 부분이 이해가 안되는데 Counter(3)[0]이면 self.stop은 3이고 index는 [0] 아닌가요? 리스트랑 숫자의 대소비교가 어떻게 되는지 궁금합니다.
 
UNIT 11.3의 참고
UNIT 39.3을 복습하세요.

data[0]으로 접근하면 내부적으로는 data.__getitem__(0)으로 호출됩니다.
data[2]로 접근하면 data.__getitem__(2)로 호출됩니다.

리스트가 아니라 내가 만든 객체에 대해서도 첨자 연산자 []로 접근하게 만들고 싶다면 __getitem__ 메서드를 정의해줘야 합니다.

예제 코드 안 보고 UNIT 39.3의 코드를 완벽하게 작성할 수 있을 정도가 되면 이해가 될 겁니다. 10번, 20번이라도 반복해서 작성해보는 게 좋습니다. 이터레이터를 작성하는 문법 구조 이해하기, 이터레이터를 사용하는 코드 이해하기, 두 가지가 되어야 합니다.
쉬운 개념은 아니니 연습이 필요합니다. 한 번 보고 이해하기 어렵습니다.

__getitem__은 원래 문법이 그렇습니다. UNIT 39.3 복습하세요.

https://docs.python.org/3/reference/datamodel.html#object.__getitem__

파이썬 공식 문서를 보면
object.__getitem__(self, key)

이렇게 하라고 되어 있습니다.

따라야 하는 문법입니다.

, 김 민석님이 작성
 

class TimeIterator() :
def __init__(self, start, stop):
self.start = start
self.stop = stop


def __getitem__(self, index):
if index < self.stop - self.start:
hour = (self.start + index)//60//60%24
minute = (self.start + index)//60%60
second = (self.start + index)%60
return '{0:02d}:{1:02d}:{2:02d}'.format(hour, minute, second)
else:
raise IndexError

초를 계산할 때 어떤식으로 풀어야할 지 감이 안잡혀 우선 힌트를 보고 작성하였습니다.

힌트를 보니 self.start + index로 초를 구하도록 되어있던데 이 코드가 이해가 안되서 디버그로 살펴보았습니다.

__getitem__(self,index)를 한 번 지날 때마다 index가 증가하는 것을 확인했습니다. 

근데 여기서 index가 0으로 초기화되어 있지도 않고 메소드를 지날 때 마다 index값이 증가하는데 이 부분이 이해가 되지 않습니다.

39.3에서도 index에 대한 초기화가 따로 되어있지 않은데 __getitem__(self,index)의 원래 문법이 이런 것인가요??



, 도장_ 관리자님이 작성
 

UNIT 39.3을 반복 학습하고, 39.7 심사문제 해설을 살펴보는 것을 추천합니다.

인덱스를 사용할 수 없는 객체에 인덱스를 사용할 수 있게 만들어 주는 것이 __getitem__입니다.

리스트에서 a[0]으로 사용할 수 있는 것은 리스트에 __getitem__이 구현되어 있기 때문입니다. a[0]을 사용하면 a.__getitem__(0)이 호출되는 것이죠.

TimeIterator를 만들었는데 map 객체로 만들었습니다. map 객체는 [] 첨자연산자를 사용할 수 없습니다. 그런데 제시된 코드를 보면 TimeIterator(start, stop)으로 map 객체를 만들었고,

TimeIterator(start, stop)[index]처럼 첨자 연산자로 접근하는 것을 알 수 있습니다.

따라서 [index]처럼 사용할 수 있게 __getitem__을 구현해야 합니다.

__getitem__을 구현할 때 index에 따라 어떤 값을 반환할지는 구현자의 선택입니다. [0]을 첫 번째 요소를 반환하는 것으로 만들지, 마지막 요소를 반환하는 것으로 만들지는 전적으로 구현자의 선택 사항이지, __getitem__(0)을 호출했을 때 무조건 첫 번째 원소를 반환해야 한다는 아닙니다.