반복 가능한 객체 요소를 순차적으로 꺼낼 수 있는 객체
__iter__ : 객체가 반복 가능한 객체인지 알아보는 메서드
__next__: 요소를 차례대로 꺼낼 수 있는 메서드
꺼낼 요소가 없으면 Stopiteration 예외 발생시켜 반복 종료
it = [1,2,3].__iter__()
print(it.__next__())
print(it.__next__())
print(it.__next__())
print(it.__next__())

iter(호출가능한 객체, 반복을 끝낼 값)
#iter함수를 활용하면 if조건문으로 매번 숫자가 2인지 검사하지 않아도 된다
import random
while True:
i = random.randint(0,5)
if i == 2:
break
print(i, end=' ')
# for문과 iter 사용
import random
for i in iter(lambda : random.randint(0,5),2): #2를 생성할 때 종료, 2는 출력 x
print(i, end=' ')

📍 __iter__ 와 iter()의 차이 📍
'__iter__'
* 클래스 내에 구현되는 메서드
* 보통 클래스의 인스턴스 메서드로 정의
iter()
* 내장 함수
* 인자로 전달된 객체의 '__iter__' 메서드를 호출하여 이터레이터 반환
# __iter__ 예시
class MyIterable:
def __init__(self,data)
self.index = 0
self.data = data
def __iter__(self):
return self
# iter() 예시
my_list = [1,2,3]
iterator = iter(my_list)
print(next(iterator)
print(next(iterator)
print(next(iterator)
# 다음 호출에서는 StopIteration 예외 발생
it = iter(range(3))
print(next(it, 10))
print(next(it, 10))
print(next(it, 10))
print(next(it, 10))

#클래스로 이터레이터 작성
class Counter:
def __init__(self, stop):
self.current = 0 #현재 숫자 유지, 0부터 지정된 숫자 직전까지 반복
self.stop = stop #반복을 끝낼 숫자
def __iter__(self): #현재 인스턴스 반환
return self
def __next__(self):
if self.current < self.stop: # 현재 숫자가 번복을 끝낼 숫자보다 작을 때
r = self.current #반환할 숫자 변수에 저장
self.current += 1 #현재 숫자를 1증가
return r #숫자를 반환
else: #현재 숫자가 반복을 끝낼 숫자보다 크거나 같을 때
raise StopIteration #예외발생
for i in Counter(3):
print(i, end=' ')

class MyIterator:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index >= len(self.data):
raise StopIteration
value = self.data[self.index]
self.index += 1
return value
def __getitem__(self, index):
if index < 0 or index >= len(self.data):
raise IndexError("Index out of range")
return self.data[index]
numbers = [1, 2, 3, 4, 5]
iterator = MyIterator(numbers)
for num in iterator:
print(num)
# 인덱스로 접근하여 값 출력
print("Index access:")
print(iterator[0]) >> 1
print(iterator[3]) >> 4
a,b,c = Counter(3)
print(a,b,c)
a,b,c,d,e = Counter(5)
print(a,b,c,d,e)

제너레이터(generator)
이터레이터를 생성해주는 함수(발생자)
def number_gen():
yield 0
yield 1
yield 2
for i in number_gen():
print(i)

def num_gen(stop):
n = 0
while n < stop:
yield n
n += 1
g = num_gen(3)
print(next(g))
print(next(g))
print(next(g))
print(next(g))

def upper_gen(x):
for i in x:
yield i.upper()
f = ['apple','pear','grape','pineapple','orange']
for i in upper_gen(f):
print(i)

def num_gen():
x = [1, 2, 3]
yield from x
for i in num_gen():
print(i)

메인루틴과 서브루틴과 cooperative routine을 가지는 서로 협력하는 루틴
def add(a,b):
c = a+b
print(c)
print('add함수')
def calc():
add(1,2)
print('clac함수')
calc()
>> calc() 메인 루틴 실행 후 add() 서브루틴 실행
* 코루틴은 메인 루틴과 서브 루틴이 서로 대등한 관계로 특정 시점에서 상대방의 코드를 실행
코루틴 객체.send(값)
변수 = yield
def number_coroutine():
while True: #코루틴을 유지하기 위해 무한루프 사용
x = (yield)
print(x)
co = number_coroutine()
next(co) #코루틴 안의 yield 코드 실행
co.send(1) #코루틴에 숫자를 보냄
co.send(2)
co.send(3)

변수 = (yield 변수)
변수 = next(코루틴객체)
변수 = 코루틴객체.send(값)
def sum_co():
total = 0
while True:
x = (yield total) #코루틴 바깥에서 값을 받아와 바깥으로 값 전달
total += x
co = sum_co()
print(next(co)) #코루틴 안의 yield까지 코드를 실행하고 코루틴에서 나온 값 출력
print(co.send(1)) #코루틴에 숫자를 보내고 코루틴에서 나온 값 출력
print(co.send(2))
print(co.send(3))

코루틴.close()
def number_co():
while True:
x = (yield)
print(x, end =' ')
co = number_co()
next(co)
for i in range(20):
co.send(i)
co.close()

def number_co():
try:
while True:
x = (yield)
print(x, end =' ')
except GeneratorExit:
print()
print('코루틴 종료')
co = number_co()
next(co)
for i in range(20):
co.send(i)
co.close()

코루틴객체.throw(예외이름, 에러 메시지)
def sum_co():
try:
total = 0
while True:
x = (yield)
total += x
except RuntimeError as e: #중간에 예외 발생시키기
print(e)
yield total
co = sum_co()
next(co)
for i in range(20):
co.send(i)
print(co.throw(RuntimeError, "예외를 코루틴 끝내기"))

변수 = yield from 코루틴()
** yield from은 python 3.3 이상부터 사용가능
def accumulate():
total = 0
while True:
x = (yield)
if x is None:
return total
total += x
def sum_co():
while True:
total = yield from accumulate() # accumulate 반환값을 가져옴
print(total)
co = sum_co()
next(co)
for i in range(1, 11): #1~10까지 반복
co.send(i) # 코루틴 accumulate에 숫자를 보냄
co.send(None) 코루틴 accumulate에 None을 보내서 숫자 누적 끝냄
for i in range(1, 101):
co.send(i)
co.send(None)

# 클래스 없이 구현할 때
numbers = [1, 2, 3, 4, 5]
iterator = iter(numbers)
while True:
try:
result = next(iterator)
print(result)
except StopIteration:
break
# 클래스로 구현할 때
class Iterator():
def __init__(self, stop):
self.current = 0
self.stop = stop
def __iter__(self):
return self
def __next__(self):
if self.current < len(self.stop):
r = self.stop[self.current]
self.current += 1
return r
else:
raise StopIteration
numbers = [1, 2, 3, 4, 5]
iterator = Iterator(numbers)
for i in iterator:
print(i, end=' ')

class Iterator():
def __init__(self, stop):
self.index = 0
self.stop = stop
def __iter__(self):
return self
def __next__(self):
if self.index < len(self.stop):
r = self.stop[self.index]
self.index += 1
return r
else:
raise StopIteration
def __getitem__(self,index):
if 0 <= index < len(self.stop):
return self.stop[index]
else:
raise StopIteration
numbers = [1, 2, 3, 4, 5]
iterator = Iterator(numbers)
print(iterator[0])
print(iterator[4])

class Fib():
def __init__(self):
self.a = 0
self.b = 1
def __iter__(self):
return self
def __next__(self):
if self.a > 100:
raise StopIteration
current = self.a
self.a, self.b = self.b, self.a + self.b
return current
fib_iter = Fib()
for number in fib_iter:
print(number)

def read_lines(filename):
with open(filename, 'r') as file:
while line := file.readline():
yield line.strip()
filename = 'show.txt'
with open(filename, 'w') as f:
f.write("First line\nSecond line\nThird line")
for line in read_lines(filename):
print(line)
