Python 강좌 : 제 42강 - 생성자
생성자(Generator)
생성자(Generator)
란 반복자(Iterator)
를 생성해주는 함수입니다.
yield
키워드를 활용해 반복자 형태를 구현할 수 있습니다.
함수 내부에 yield
가 존재하면, 함수 전체를 생성자(Generator)
로 간주합니다.
일반적인 함수는 스코프(Scope)내의 코드를 모두 실행시킨 후, 소멸합니다.
하지만, 생성자 함수는 스코프 내에서 일시 중지해가며 실행시킬 수 있습니다.
즉, 함수가 실행되고 있는 도중에 중지하고 값을 수정할 수도 있습니다.
생성자(Generator) 사용하기
- 결과
- First
[0, 1]
———
Second
[0, 1, 2]
———
Third
END
———
END
———
생성자(Generator)
는 yield
키워드를 통해 구현할 수 있습니다.
반복자(Iterator)
를 사용해 생성자 객체를 반환합니다.
next()
함수를 실행시킬 때, yield
키워드 구문에서 일시 중지하게 됩니다.
함수를 초기화하는 것이 아닌 yield
구문에서 중지합니다.
함수 내부의 변수나 멤버는 유지되며, 변경이 가능합니다.
yield
키워드가 더 이상 남아있지 않을 때에는 남은 구문을 모두 출력하며, StopIteration 예외를 발생시킵니다.
하지만, next()
함수에 StopIteration 예외 발생시, 반환할 값을 설정할 수 있습니다.
StopIteration 예외 발생 이후에도 반환한다면, 더 이상 남아있는 구문이 없어 END
값만 반환합니다.
반복 가능한(iterable) 형식 반환하기
- 결과
- [[1, 2, 3]]
yield
키워드를 통해 반복 가능한(iterable)
객체를 반환할 경우, 값이 묶여 반환됩니다.
이를 해결하기 위해 from
키워드를 추가해 한 번에 반환할 수 있습니다.
- 결과
- [1, 2, 3]
yield from iterable
형태로 값을 반환하면, 객체를 두 번 묶지 않고 반환할 수 있습니다.
이를 통해 불필요한 반복문이나 객체를 한 번 더 푸는 작업을 진행하지 않아도 됩니다.
코루틴(Coroutine)
- 결과
- Value:A, Count:0
Value:200, Count:1
Value:50, Count:2
여태까지 사용하던 함수는 서브루틴(Subroutine)
함수로, 진입 지점이 하나이며 return
키워드를 통해 종료되었습니다.
하지만, 생성자(Generator)
는 함수 실행 도중에 일시 정지를 할 수 있으므로, 일시 중지한 시점에서 값을 추가로 입력할 수 있습니다.
즉, 진입 지점이 여러 개로 늘어나게 되며 값을 주고 받을 수도 있게됩니다. 이를 코루틴(Coroutine)
이라 합니다.
코루틴 함수에서 value = yield c
의 형태로 사용한다면, 생성자 함수로 값을 보낼 수 있습니다.
여기서 값을 보내기 위해서는 함수를 초기화해야합니다.
coroutine()
함수가 생성된 이후, cor.send(None)
또는 next(cor)
를 활용해 생성자 함수를 초기화합니다.
이후, cor.send()
메서드를 통해 값을 전달할 수 있습니다.
앞서, yield
구문을 만나면 해당 구문에서 일시 정지하였지만, 코루틴 함수는 해당 블록(for문 내부)
을 모두 실행시킵니다.
그러므로, print()
함수가 실행됩니다. 즉, 값을 전달하고 블록을 모두 실행시킬 수 있습니다.
- 결과
- next() - Value:A, Count:0
send() - Value:A, Count:0
next() - Value:200, Count:1
send() - Value:200, Count:1
next() - Value:50, Count:2
send() - Value:50, Count:2
value
에 yield c
를 할당한 이후에 yield
키워드를 추가해 반이중 방식(half-duplex)
형태와 흡사한 함수를 구현할 수 있습니다.
cor.send()
메서드를 통해 값을 전달하는 방식과 동일하지만, 함수 내부에 yield value
가 추가되어 주고 받는 형식이 됩니다.
send()
메서드에서는 다음 번째 yield value
가 만나기 전까지 모든 구문을 실행합니다.
yield value
구문은 next()
함수를 통해 넘어갈 수 있었습니다.
값을 다시 반환받기 위해서는 next(cor)
를 활용합니다.
즉, 값을 보낼때는 cor.send()
를 사용하며, 값을 받을때는 next()
를 사용한다 볼 수 있습니다.
- Tip :
cor.send()
의 반환값은value
값을 반환하며,next(cor)
의 반환값은c
값을 반환합니다.
오류 발생(throw)
- 결과
- next() - Value:A, Count:0
Error 0
next() - Value:200, Count:1
Error 1
Error 2
코루틴(Coroutine)
도중 오류를 강제로 발생시켜, 예외 처리를 진행할 수 있습니다.
cor.throw()
를 통해, 강제로 오류를 발생시킬 수 있습니다.
오류를 발생시켜도, 진행 중인 Count
의 값은 증가하며, next()
함수와 동일한 기능을 합니다.
즉, 입력 → 출력
, 입력 → 오류
, 입력 → 출력
구조의 형태로도 구현이 가능합니다.
도중에 오류를 발생시키는 이유는, 함수 내부적으로 오류를 처리하는 것이 아닌 외부에서 처리하기 위함입니다.
이를 통해 특정 오류 상황을 알릴 수 있으며, 코드가 더 간결해질 수 있습니다.
생성자(Generator) 종료하기
- 결과
- next() - Value:A, Count:0
END
현재 생성자(Generator)
는 무한히 반복되는 구조입니다.
코드 상에 종료 구문이 없으므로 끝이 존재하지 않습니다.
하지만, close()
함수를 통해 강제로 생성자를 종료할 수 있습니다.
cor.close()
가 호출된 이후 부터 StopIteration
예외를 발생시킵니다.
즉, 더 이상 참조할 수 없는 형태로 변경합니다.
댓글 남기기