🔍 버전 비교: fastapi-lifespan
히스토리로 돌아가기
추가된 줄
삭제된 줄
변경된 줄
버전 3 | 버전 2 | ||||
---|---|---|---|---|---|
5 | asynccontextmanager 에 관해서 알아보기 전에 우리는 **ContextManager** 에 대한 개념이 필요하다. ContextM | 5 | asynccontextmanager 에 관해서 알아보기 전에 우리는 **ContextManager** 에 대한 개념이 필요하다. ContextM | ||
> | anager 는 `with` 문과 함께 실행시간에 의존하는 컨텍스트를 생성하게 된다. | > | anager 는 `with` 문과 함께 실행시간에 의존하는 컨텍스트를 생성하게 된다. | ||
6 | 6 | ||||
7 | 따라서 메소드도 `__enter__()` 와 `__exit__()`(이와 같이 파이썬에서 underbar 두개를 붙이면 던더메소드[^1] 라고 | 7 | 따라서 메소드도 `__enter__()` 와 `__exit__()`(이와 같이 파이썬에서 underbar 두개를 붙이면 던더메소드[^1] 라고 | ||
> | 한다) 을 가지고 있다. 즉, 컨텍스트에 진입할때 `__enter__()` 가 호출되고 컨텍스트와 관련된 내용을 반환하고, 처리를 마친뒤에는 _ | > | 한다) 을 가지고 있다. 즉, 컨텍스트에 진입할때 `__enter__()` 가 호출되고 컨텍스트와 관련된 내용을 반환하고, 처리를 마친뒤에는 _ | ||
> | _exit__() 함수가 호출되게 된다. 아래 코드 예시를 보면 조금 더 쉬울 것 이다. | > | _exit__() 함수가 호출되게 된다. 아래 코드 예시를 보면 조금 더 쉬울 것 이다. | ||
n | 8 | n | |||
9 | ```python | ||||
10 | class ManagedResource: | ||||
11 | def __init__(self, *args, **kwds): | ||||
12 | self.args = args | ||||
13 | self.kwds = kwds | ||||
14 | self.resource = None | ||||
15 | |||||
16 | def __enter__(self): | ||||
17 | # 자원을 얻는 코드, 예를 들어: | ||||
18 | self.resource = acquire_resource(*self.args, **self.kwds) | ||||
19 | return self.resource | ||||
20 | |||||
21 | def __exit__(self, exc_type, exc_val, exc_tb): | ||||
22 | # 자원을 해제하는 코드, 예를 들어: | ||||
23 | release_resource(self.resource) | ||||
24 | ``` | ||||
25 | |||||
26 | 보면 `__enter__` 에서 리소스를 취득한 뒤에 리소스(컨텍스트와 연관된)를 반환 받고, 받는 쪽에서 호출이 끝난 뒤 `__exit__` | ||||
> | 에서 **realeas_resource(resource)** 함수가 호출된다. 이러한 contextmanager 를 조금 더 쉽게 만들기 위한 | ||||
> | 팩터리 메서드[^2]를 호출하는 데코레이터 방식을 이용하면 조금 더 간결하게 구현이 가능하다. 아래 예시를 한번 보자. | ||||
27 | 8 | ||||
28 | ```python | 9 | ```python | ||
29 | from contextlib import contextmanager | 10 | from contextlib import contextmanager | ||
39 | release_resource(resource) | 20 | release_resource(resource) | ||
40 | ``` | 21 | ``` | ||
41 | 22 | ||||
n | 42 | `@contextmanager` 와 같은 데코레이터 방식은 이러한 컨텍스트매니저를 편리하게 만들 수 있도록 도와주는 **팩터리 메서드**이다. | n | 23 | 보면 리소스를 취득한뒤에 리소스(컨텍스트와 연관된)를 반환한 뒤에 받는 쪽에서 호출이 끝난 뒤 **realeas_resource(resource |
> | 조금 더 직관적으로 확인하기 위해 코드로 한번 확인해보자. | > | )** 함수가 호출된다. 조금 더 직관적으로 확인하기 위해 코드로 한번 확인해보자. | ||
43 | 24 | ||||
44 | ```python | 25 | ```python | ||
45 | import asyncio | 26 | import asyncio | ||
58 | asyncio.run(main()) | 39 | asyncio.run(main()) | ||
59 | ``` | 40 | ``` | ||
60 | 41 | ||||
n | 61 | 이 함수의 실행결과는 어떨까? 아래에서 한번 확인해보자. | n | ||
62 | |||||
63 | ```python | ||||
64 | before executing function | ||||
65 | hello | ||||
66 | after executing function | ||||
67 | ``` | ||||
68 | |||||
69 | 위와 같이 실행되는 이유는 yield 의 윗 부분이 `__enter__` 의 역할을 하고 yield 값을 반환하고 난 뒤, 해당 값을 받아 외부 | ||||
> | 에서 사용하고 다시 문맥이 종료되는 시점(with 문이 끝나는 시점)에 yield 하위 코드가 실행된다. 코드를 보면 어렵지 않고 코루틴에 익숙 | ||||
> | 하다면 yield 또한 익숙할 것이다. 그렇다면 FastAPI 는 이 asynccontextmanager 를 어떻게 이용해서 구현하고 있을까? | ||||
> | 예상이 가지 않는가? | ||||
70 | |||||
71 | ## lifespan | ||||
72 | |||||
73 | |||||
74 | |||||
75 | --- | 42 | --- | ||
76 | [^1]: 던더메소드는 객체에 따라 행동이 정해져있는 메소드로 이 객체가 어떤 던더메소드를 가지고 있는지 알기 위해서는 `dir` 함수를 사용하 | 43 | [^1]: 던더메소드는 객체에 따라 행동이 정해져있는 메소드로 이 객체가 어떤 던더메소드를 가지고 있는지 알기 위해서는 `dir` 함수를 사용하 | ||
> | 면 된다. | > | 면 된다. | ||
t | 77 | [^2]: 팩토리메소드는 쉽게 이야기 하면 객체를 생성하는 메소드로 보통 특정한 형태로 객체를 생성하기 위해 주로 이용한다. | t |