μ½”λ“œ - 패캠 μˆ˜μ—… μ½”λ“œ μ°Έκ³  (패캠 μˆ˜μ—… 정리)

 

 

<이전 κΈ€>

https://silvercoding.tistory.com/29

 

[python 심화] 12. λ‚΄λΆ€ iter ν•¨μˆ˜, μ œλ„ˆλ ˆμ΄ν„°(Generator)

μ½”λ“œ - 패캠 μˆ˜μ—… μ½”λ“œ μ°Έκ³  (패캠 μˆ˜μ—… 정리) <이전 κΈ€> https://silvercoding.tistory.com/28 https://silvercoding.tistory.com/27 https://silvercoding.tistory.com/26 https://silvercoding.tistory.com/25..

silvercoding.tistory.com

 

 

* yield : 메인 루틴 (μˆœμ°¨μ§„ν–‰ - ν•˜λ‚˜μ˜ 흐름) <-> μ„œλΈŒλ£¨ν‹΄ (ν•¨μˆ˜κ°€ 호좜되면 ν•¨μˆ˜κ°€ μžˆλŠ” 곳으둜) 이 루틴 λ‘κ°œλ₯Ό λ™μ‹œμ— ν•  수 있게 ν•΄μ£ΌλŠ” 게 yield이닀. 

* 코루틴 μ œμ–΄ , 코루틴  μƒνƒœ, μ–‘λ°©ν–₯ κ°’ 전솑 (μ–‘λ°©ν–₯ 톡신) 

* μ„œλΈŒ 루틴 : λ©”μΈλ£¨ν‹΄μ—μ„œ 리턴에 μ˜ν•΄ 호좜 λΆ€λΆ„μœΌλ‘œ λŒμ•„μ™€ λ‹€μ‹œ ν”„λ‘œμ„ΈμŠ€ 

* 코루틴 : 루틴 μ‹€ν–‰ 쀑 멈좀 κ°€λŠ₯ -> νŠΉμ • μœ„μΉ˜λ‘œ λŒμ•„κ°”λ‹€κ°€ -> λ‹€μ‹œ μ›λž˜ μœ„μΉ˜λ‘œ λŒμ•„μ™€ μˆ˜ν–‰ κ°€λŠ₯ -> λ™μ‹œμ„± ν”„λ‘œκ·Έλž˜λ° κ°€λŠ₯ν•˜κ²Œ ν•΄μ€Œ 

*μ“°λ ˆλ“œ : μ‹±κΈ€μ“°λ ˆλ“œ -> λ©€ν‹°μ“°λ ˆλ“œ -> λ³΅μž‘ν•˜λ‹€! (κ³΅μœ λ˜λŠ” μžμ›μ— λŒ€ν•œ κ΅μ°©μƒνƒœ λ°œμƒ κ°€λŠ₯성이 μžˆμœΌλ―€λ‘œ 주의깊게 μ½”λ”©ν•΄μ•Ό 함) / μ»¨ν…μŠ€νŠΈ μŠ€μœ„μΉ­ λΉ„μš© λ°œμƒ, μžμ› μ†ŒλΉ„ κ°€λŠ₯μ„± 증가 

 

 

- 코루틴 예제1 

def coroutine1():
    print('>>> coroutine started.')
    i = yield 
    print('>>> coroutine received : {}'.format(i))

μ €λ²ˆ κΈ€μ—μ„œλŠ” yield i <-- 이런 μ‹μœΌλ‘œ μ‚¬μš©ν–ˆλŠ”λ° , μ΄λ²ˆμ—λŠ” i = yield 의 ν˜•νƒœλ‘œ μ‚¬μš©ν•˜μ—¬ 메인 λ£¨ν‹΄μ—μ„œ 값을 전달 받을 수 μžˆλ‹€. 

 

 

* μ œλ„ˆλ ˆμ΄ν„° μ„ μ–Έ

c1 = coroutine1()
print('EX1-1 - ', c1, type(c1))

 EX1-1 -  <generator object coroutine1 at 0x000001430D3574F8> <class 'generator'> 

μ œλ„ˆλ ˆμ΄ν„° 객체λ₯Ό μƒμ„±ν•˜μ˜€λ‹€. 

 

next(c1)
next(c1)

 >>> coroutine started. 
 >>> coroutine received : None 
 Traceback (most recent call last): 
  File "c:/Users/./Desktop/python_high/chapter06_02.py", line 35, in <module>  
    next(c1) 
 StopIteration 

μœ„μ™€κ°™μ΄ 값을 μ „μ†‘ν•˜μ§€ μ•ŠμœΌλ©΄ 기본적으둜 None을 μ „μ†‘ν•œλ‹€. 

 

* κ°’ 전솑 

next(c1)
c1.send(100)

 >>> coroutine started. 
 >>> coroutine received : 100 
 Traceback (most recent call last): 
  File "c:/Users/./Desktop/python_high/chapter06_02.py", line 41, in <module>  
    c1.send(100) 
 StopIteration 

μ΄λ ‡κ²Œ next() λŒ€μ‹  send()둜 값을 전달할 수 μžˆλ‹€. 

 

 

* 잘λͺ»λœ μ‚¬μš© 

c2 = coroutine1()
c2.send(100) # μ˜ˆμ™Έ λ°œμƒ

 Traceback (most recent call last): 
  File "c:/Users/./Desktop/python_high/chapter06_02.py", line 45, in <module>  
    c2.send(100) # μ˜ˆμ™Έ λ°œμƒ 
 TypeError: can't send non-None value to a just-started generator 

next()λ₯Ό ν˜ΈμΆœν•˜μ§€ μ•Šκ³  , μ²˜μŒλΆ€ν„° sendλ₯Ό μ‚¬μš©ν•˜λ©΄ μ˜ˆμ™Έκ°€ λ°œμƒν•˜κ²Œ λœλ‹€! ( λ’€μ—μ„œ nextλ₯Ό ν˜ΈμΆœν•˜μ§€ μ•Šμ•„λ„ λ˜λŠ” 방법을 배울 것이닀. )

 

 

 

 

 

 

 

 

 

- 코루틴 예제 2 

* GEN_CREATED : 처음 λŒ€κΈ° μƒνƒœ 

* GEN_RUNNING : μ‹€ν–‰ μƒνƒœ 

* GEN_SUSPENDED : yield λŒ€κΈ° μƒνƒœ 

* GEN_CLOSED : μ‹€ν–‰ μ™„λ£Œ μƒνƒœ 

 

def coroutine2(x):
    print('>>> coroutine started : {}'.format(x))
    y = yield x 
    print('>>> coroutine received : {}'.format(y))
    z = yield x + y 
    print('>>> coroutine received : {}'.format(z))

 

c3 = coroutine2(10)

coroutine2 ν•¨μˆ˜λ₯Ό μƒμ„±ν•˜κ³  객체λ₯Ό ν• λ‹Ήν•΄ μ€€λ‹€. xλŠ” 10으둜 λ„£μ–΄μ€€λ‹€. 

from inspect import getgeneratorstate
from typing_extensions import Literal

print('EX1-2 - ', getgeneratorstate(c3))

print(next(c3))

print('EX1-3 - ', getgeneratorstate(c3))

print(c3.send(15))
print(c3.send(20)) # μ˜ˆμ™Έ

 EX1-2 -  GEN_CREATED 

getgeneratorstateλ₯Ό μ΄μš©ν•˜μ—¬ μ œλ„ˆλ ˆμ΄ν„°μ˜ μƒνƒœλ₯Ό κ°€μ Έμ™€μ„œ 확인할 수 μžˆλ‹€. μš°μ„  객체만 μƒμ„±ν–ˆμ„ λ•Œ 처음 λŒ€κΈ° μƒνƒœμž„μ„ 확인할 수 μžˆλ‹€. 
 >>> coroutine started : 10 
 10 

x값이 λ°˜ν™˜λ˜κ³ , 이 μƒνƒœμ—μ„œ λŒ€κΈ°ν•œλ‹€. 
 EX1-3 -  GEN_SUSPENDED 

yield λŒ€κΈ° μƒνƒœ μž„μ„ 확인할 수 μžˆλ‹€. 
 >>> coroutine received : 15 
 25 

κ·Έλ‹€μŒ send둜 15λ₯Ό 보내면 멈좰있던 yield μƒνƒœμ—μ„œ y에 κ°’ 15κ°€ μ „λ‹¬λœλ‹€. print문으둜 15κ°€ 잘 μ „λ‹¬λœ 것을 λ³Ό 수 있고, κ·Έ λ‹€μŒ yield의 x + y κ°€ λ°˜ν™˜λ˜κ³  μ΄μƒνƒœμ—μ„œ λ©ˆμΆ˜λ‹€. 

 >>> coroutine received : 20 

또 λ‹€μ‹œ send둜 20을 보내면 yield λŒ€κΈ° μƒνƒœμ—μ„œ λ©ˆμΆ”μ–΄ 있던 z에 값이 μ „λ‹¬λœ 것을 λ³Ό 수 μžˆλ‹€. 

 Traceback (most recent call last): 
  File "c:/Users/./Desktop/python_high/chapter06_02.py", line 78, in <module>  
    print(c3.send(20)) # μ˜ˆμ™Έ 
 StopIteration 

κ·Έλ‹€μŒ yieldκ°€ μ—†μœΌλ―€λ‘œ 였λ₯˜κ°€ λ‚˜κ²Œ λœλ‹€. 

 

 

 

 

 

 

 

 

 

 

- λ°μ½”λ ˆμ΄ν„° νŒ¨ν„΄

: nextλ₯Ό ν˜ΈμΆœν•˜μ§€ μ•Šμ•„λ„ λœλ‹€! 

<λ°μ½”λ ˆμ΄ν„° ν¬μŠ€νŒ…>

https://silvercoding.tistory.com/26

 

[python 심화] 9. λ³€μˆ˜ λ²”μœ„, Closure, Decorator

μ½”λ“œ - 패캠 μˆ˜μ—… μ½”λ“œ μ°Έκ³  (패캠 μˆ˜μ—… 정리) <이전 κΈ€> https://silvercoding.tistory.com/25 이번 ν¬μŠ€νŠΈμ—μ„œλŠ” λ°μ½”λ ˆμ΄ν„°λ₯Ό μ•Œμ•„λ³Ό 것이닀. λ°μ½”λ ˆμ΄ν„°λŠ” μ–΄λ ΅λ‹€κ³  λŠλΌλŠ” 것이 λ‹Ήμ—°ν•˜λ‹€. λ°μ½”λ ˆμ΄ν„°

silvercoding.tistory.com

λ‚΄λΆ€μ μœΌλ‘œ λŒμ•„κ°€λŠ” 게 항상 ν—·κ°ˆλ €μ„œ 보고였기

from functools import wraps

def coroutine(func):
    '''Decorator run until yield'''
    @wraps(func)
    def primer(*args, **kwargs):
        gen = func(*args, **kwargs)
        next(gen)
        return gen
    return primer

μ œλ„ˆλ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•  λ•Œ μ²˜μŒμ— nextλ₯Ό ν˜ΈμΆœν•˜μ§€ μ•Šκ³  λ°”λ‘œ send둜 값을 보내면 였λ₯˜κ°€ 났닀. μ΄λ²ˆμ—λŠ” μœ„ λ°μ½”λ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•˜μ—¬ λ°”λ‘œ 값을 μ „μ†‘ν•˜λ„λ‘ λ§Œλ“ λ‹€. 

@coroutine
def sumer():
    total = 0 
    term = 0 
    while True:
        term = yield total
        total += term
su = sumer()

λ°μ½”λ ˆμ΄ν„° @coroutine을 μž‘μ„±ν•΄ μ£Όκ³ , 객체 suλ₯Ό μƒμ„±ν•˜μ˜€λ‹€. 

print('EX2-1 - ', su.send(100))
print('EX2-2 - ', su.send(40))
print('EX2-3 - ', su.send(60))

 EX2-1 -  100 
 EX2-2 -  140 
 EX2-3 -  200 

λ°μ½”λ ˆμ΄ν„°λ‘œ 인해 nextκ°€ ν˜ΈμΆœλ˜μ—ˆκ³ , yieldμ—μ„œ λ©ˆμΆ”μ–΄ μžˆλŠ” μƒνƒœμ΄λ‹€. 이 μƒνƒœμ—μ„œ send둜 100을 μ „μ†‘ν•˜λ©΄ term에 100이 λ“€μ–΄κ°€κ³ , total은 0+100=100이 되고, λ‹€μ‹œ yieldμ—μ„œ total이 λ°˜ν™˜λ˜κ³  λ©ˆμΆ˜λ‹€. κ·Έλ‹€μŒ send둜 40을 μ „μ†‘ν•˜λ©΄ term에 40이 λ“€μ–΄κ°€κ³ , total=100+40=140이 λ˜μ–΄ λ‹€μ‹œ yieldλ₯Ό λ§Œλ‚ λ•ŒκΉŒμ§€ while문이 λŒμ•„ total을 λ°˜ν™˜ν•˜κ³ , λ©ˆμΆ˜λ‹€. 60도 λ§ˆμ°¬κ°€μ§€λ‘œ λŒμ•„κ°€μ„œ 200이 λ°˜ν™˜λ˜λŠ” 것을 λ³Ό 수 μžˆλ‹€. 

 

 

 

 

 

 

 

 

- 코루틴 예제 3 (μ˜ˆμ™Έ 처리) 

class SampleException(Exception):
    '''μ„€λͺ…에 μ‚¬μš©ν•  μ˜ˆμ™Έ μœ ν˜•'''
def coroutine_except():
    print('>> coroutine started')
    try: 
        while True:
            try:
                x = yield
            except SampleException:
                print('-> SampleException handled. Continuing..') 
            else:
                print('-> coroutine received : {}'.format(x))
    finally:
        print('-> coroutine ending')

μœ„μ—μ„œ λ§Œλ“€μ–΄ 놓은 SampleException을 μ΄μš©ν•˜μ—¬ μ˜ˆμ™Έμ²˜λ¦¬λ₯Ό ν•΄μ€€λ‹€. 

exe_co = coroutine_except()

객체 생성

print('EX3-1 - ', next(exe_co))
print('EX3-2 - ', exe_co.send(10))
print('EX3-3 - ', exe_co.send(100))
print('EX3-4 - ', exe_co.throw(SampleException))
print('EX3-5 - ', exe_co.send(1000))
print('EX3-6 - ', exe_co.close()) # GEN_CLOSED 
print('EX3-7 - ', exe_co.send(10)) # μ—λŸ¬

 >> coroutine started 
 EX3-1 -  None 
 -> coroutine received : 10 
 EX3-2 -  None 
 -> coroutine received : 100 
 EX3-3 -  None 
 -> SampleException handled. Continuing.. 
 EX3-4 -  None 
 -> coroutine received : 1000 
 EX3-5 -  None 
 -> coroutine ending 
 EX3-6 -  None 
 Traceback (most recent call last): 
  File "c:/Users/./Desktop/python_high/chapter06_02.py", line 146, in <module>  
    print('EX3-7 - ', exe_co.send(10)) # μ—λŸ¬ 
 StopIteration 

EX3-4 μ—μ„œ throw()λ₯Ό μ‚¬μš©ν•˜μ—¬ μ˜ˆμ™Έμ²˜λ¦¬λ₯Ό ν•  수 μžˆλ‹€. μ˜ˆμ™Έλ₯Ό 작고 λ‹€μ‹œ yield둜 κ°€μ„œ None을 λ°˜ν™˜ν•˜κ³  λ©ˆμΆ”μ–΄ μžˆλŠ” 것을 λ³Ό 수 μžˆλ‹€. κ·Έλž˜μ„œ λ‹€μ‹œ send둜 값을 전솑해도 λ™μž‘μ„ ν•˜κ³ , μ œλ„ˆλ ˆμ΄νŠΈλ₯Ό μ•„μ˜ˆ 끝내고 μ‹Άλ‹€λ©΄ close()λ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€. close()λ₯Ό 호좜 ν•œ ν›„ , send둜 값을 μ „μ†‘ν•˜λ €κ³  ν•˜λ©΄ 였λ₯˜κ°€ λ‚˜λŠ” 것을 μ•Œ 수 μžˆλ‹€. 

 

 

 

 

 

 

 

 

 

 

 

- 코루틴 예제 4 (return) 

def averager_re():
    total = 0.0
    cnt = 0 
    avg = None
    while True:
        term = yield
        if term is None:
            break
        total += term
        cnt += 1
        avg = total / cnt 
    return 'Average : {}'.format(avg)
avger2 = averager_re()

κ°’μœΌλ‘œ None을 보낼 λ•ŒκΉŒμ§€ while문이 μ‹€ν–‰λ˜λ„λ‘ ν•˜κ³  , λ³΄λ‚΄λŠ” 값을 λͺ¨λ‘ λ”ν•΄μ„œ 평균을 λ‚΄μ£ΌλŠ” ν•¨μˆ˜μ΄λ‹€. 

next(avger2)

avger2.send(10)
avger2.send(30)
avger2.send(50)

μœ„μ™€ 같이 값을 전달해쀀닀. 

try:
    avger2.send(None)
except StopIteration as e:
    print('EX4-1 - ', e.value)

 EX4-1 -  Average : 30.0 

None을 μ „μ†‘ν•˜μ—¬ whileλ¬Έμ—μ„œ νƒˆμΆœν•˜κ³  , μ˜ˆμ™Έμ²˜λ¦¬λ‘œ ν•¨μˆ˜μ˜ 리턴 값을 받을 수 μžˆλ‹€. 

 

 

 

 

 

 

 

 

 

 

 

 

- 코루틴 예제 4 (yield from) (3.7 -> await

: 쀑첩 코루틴 처리 

 

(1) yield from λ―Έμ‚¬μš© 

def gen1():
    for x in 'AB':
        yield x 
    for y in range(1, 4):
        yield y

μ œλ„ˆλ ˆμ΄ν„° ν•¨μˆ˜λ₯Ό 생성해 μ€€λ‹€.

t1 = gen1()
print('EX5-1 - ', next(t1))
print('EX5-2 - ', next(t1))
print('EX5-3 - ', next(t1))
print('EX5-4 - ', next(t1))
print('EX5-5 - ', next(t1))
print('EX5-6 - ', next(t1)) # StopIteration

 EX5-1 -  A 
 EX5-2 -  B 
 EX5-3 -  1 
 EX5-4 -  2 
 EX5-5 -  3 
 Traceback (most recent call last): 
  File "c:/Users/./Desktop/python_high/chapter06_02.py", line 198, in <module> 
    print('EX5-6 - ', next(t1)) # StopIteration 
 StopIteration 

μ•žμ—μ„œ ν•΄μ™”λ˜ 것 처럼 nextλ₯Ό ν˜ΈμΆœν–ˆμ„ λ•Œ 더 이상 λ§Œλ‚  yieldκ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ Stopiteration μ˜ˆμ™Έκ°€ λ‚˜κ²Œ λœλ‹€. 

t2 = gen1()
print('EX5-7 - ', list(t2))

 EX5-7 -  ['A', 'B', 1, 2, 3] 

μ΄λ ‡κ²Œ 리슀트 객체둜 받아쀄 μˆ˜λ„ μžˆλ‹€. 

 

 

 

 

(2) yield from μ‚¬μš© 

def gen2():
    yield from 'AB'
    yield from range(1, 4)

이와 같이 yield from을 μ‚¬μš©ν•˜λ©΄ μœ„μ˜ μ˜ˆμ‹œ 처럼 for문을 μ‚¬μš©ν•˜μ§€ μ•Šμ•„λ„ 되고 , κ°„λ‹¨ν•˜κ²Œ 두 μ€„λ‘œ μž‘μ„±ν•  수 μžˆλ‹€. 

t3 = gen2()
print('EX6-1 - ', next(t3))
print('EX6-2 - ', next(t3))
print('EX6-3 - ', next(t3))
print('EX6-4 - ', next(t3))
print('EX6-5 - ', next(t3))
print('EX5-6 - ', next(t3)) # StopIteration

 EX6-1 -  A 
 EX6-2 -  B 
 EX6-3 -  1 
 EX6-4 -  2 
 EX6-5 -  3 
 Traceback (most recent call last): 
  File "c:/Users/sooki/Desktop/python_high/chapter06_02.py", line 217, in <module> 
    print('EX5-6 - ', next(t3)) # StopIteration 
 StopIteration 

(1)번 μ˜ˆμ œμ™€ λ˜‘κ°™μ΄ λ‚˜μ˜€λŠ” 것을 λ³Ό 수 μžˆλ‹€. 

t4 = gen2()
print('EX6-7 - ', list(t4))

 EX6-7 -  ['A', 'B', 1, 2, 3] 

list도 λ§ˆμ°¬κ°€μ§€λ‘œ λ™μΌν•˜κ²Œ λ‚˜μ˜¨λ‹€. 

 

 

 

 

 

* yield from 예제 +1 

def gen3_sub():
    print('Sub coroutine')
    x = yield 10 
    print('Recv: ', str(x))
    x = yield 100
    print('Recv: ', str(x))
    
def gen4_main():
    yield from gen3_sub()

μœ„μ™€ 같이 sub coroutine으둜 ν•¨μˆ˜λ₯Ό μ„ μ–Έν•΄ 놓고 , main coroutineμ—μ„œ yield from 으둜 μž‘μ—…μ„ 해쀄 수 μžˆλ‹€. 

t5 = gen4_main()

print('EX7-1 - ', next(t5))
print('EX7-2 - ', t5.send(7))
print('EX7-3 - ', t5.send(77)) # 였λ₯˜

 Sub coroutine 
 EX7-1 -  10 
 Recv:  7 
 EX7-2 -  100 
 Recv:  77 
 Traceback (most recent call last): 
  File "c:/Users/sooki/Desktop/python_high/chapter06_02.py", line 247, in <module> 
    print('EX7-2 - ', t5.send(77)) 
 StopIteration 

 

 

 

 

 

 

 

 

+ Recent posts