contextvars — 컨텍스트 변수¶
이 모듈은 컨텍스트-로컬 상태를 관리, 저장, 액세스하기 위한 API를 제공합니다. ContextVar 클래스는 컨텍스트 변수 를 선언하고 사용하는 데 쓰입니다. copy_context() 함수와 Context 클래스는 비동기 프레임워크에서 현재 컨텍스트를 관리하는 데 사용해야 합니다.
상태가 있는 컨텍스트 관리자는 동시성 코드에서 상태가 예기치 않게 다른 코드로 유출되는 것을 방지하기 위해 threading.local() 대신 컨텍스트 변수를 사용해야 합니다.
자세한 내용은 PEP 567을 참조하십시오.
Added in version 3.7.
컨텍스트 변수¶
- class contextvars.ContextVar(name[, *, default])¶
이 클래스는 새로운 컨텍스트 변수를 선언하는 데 사용됩니다. 예:
var: ContextVar[int] = ContextVar('var', default=42)
필수 name 매개 변수는 인트로스팩션 및 디버그 목적으로 사용됩니다.
선택적 키워드 전용 default 매개 변수는 변수에 대한 값이 현재 컨텍스트에서 발견되지 않으면
ContextVar.get()에 의해 반환됩니다.중요: 컨텍스트 변수는 최상위 모듈 수준에서 만들어져야 하고 클로저에서 만들어져서는 안 됩니다.
Context객체는 컨텍스트 변수에 대해 강한 참조를 유지해서 컨텍스트 변수가 제대로 가비지 수집되지 못하게 합니다.ContextVars는 포함된 값의 타입을 가지는 :ref:`generic <generics>`입니다.- name¶
변수의 이름. 읽기 전용 프로퍼티입니다.
Added in version 3.7.1.
- get([default])¶
현재 컨텍스트의 컨텍스트 변수에 대한 값을 반환합니다.
현재 컨텍스트에서 변수에 대한 값이 없는 경우 메서드는:
제공된 경우 메서드의 default 인자 값을 반환합니다; 또는
생성 시에 제공된 경우, 컨텍스트 변수의 기본값을 반환합니다; 또는
LookupError를 발생시킵니다.
- set(value)¶
현재 컨텍스트에서 컨텍스트 변수의 새 값을 설정하려면 호출합니다.
필수 value 인자는 컨텍스트 변수의 새 값입니다.
ContextVar.reset()메서드를 통해 변수를 이전 값으로 복원하는 데 사용할 수 있는Token객체를 반환합니다.편의를 위해, 토큰 객체를 컨텍스트 관리자로 사용할 수 있어 :meth:`ContextVar.reset`을 수동으로 호출하는 것을 방지합니다:
var = ContextVar('var', default='default value') with var.set('new value'): assert var.get() == 'new value' assert var.get() == 'default value'
다음의 약어입니다:
var = ContextVar('var', default='default value') token = var.set('new value') try: assert var.get() == 'new value' finally: var.reset(token) assert var.get() == 'default value'
Added in version 3.14: 토큰을 컨텍스트 관리자로 사용하기 위한 지원이 추가되었습니다.
- reset(token)¶
token 을 생성 한
ContextVar.set()이 사용되기 전의 값으로 컨텍스트 변수를 재설정합니다.예를 들면:
var = ContextVar('var') token = var.set('new value') # 'var'를 사용하는 코드; var.get() 은 'new value'를 반환합니다. var.reset(token) # reset 호출 후에 var에는 값이 다시 없으므로, var.get() 은 # LookupError를 발생시킵니다.
같은 token 은 두 번 사용할 수 없습니다.
- class contextvars.Token¶
Token 객체는
ContextVar.set()메서드에 의해 반환됩니다. 이는 해당 set 이전의 값으로 변수의 값을 되돌리는 데ContextVar.reset()메서드에 전달될 수 있습니다. 단일 토큰은 컨텍스트 변수를 한 번 이상 재설정할 수 없습니다.토큰은 :ref:`context manager protocol <context-managers>`를 지원하여 컨텍스트 변수를 자동으로 재설정합니다. :meth:`ContextVar.set`을 참조하십시오.
토큰은 자신을 생성한 :class:`ContextVar`와 동일한 유형에 대한 :ref:`generic <generics>`입니다.
Added in version 3.14: 컨텍스트 관리자로서 사용하기 위한 지원이 추가되었습니다.
- var¶
읽기 전용 프로퍼티. 토큰을 생성 한
ContextVar객체를 가리 킵니다.
- old_value¶
읽기 전용 프로퍼티. 토큰을 생성 한
ContextVar.set()메서드 호출 전 변수의 값으로 설정됩니다. 호출 전에 변수가 설정되지 않았으면Token.MISSING을 가리킵니다.
- MISSING¶
Token.old_value에 의해 사용되는 표지 객체.
수동 컨텍스트 관리¶
- contextvars.copy_context()¶
현재
Context객체의 복사본을 반환합니다.다음 코드 조각은 현재 컨텍스트의 복사본을 가져와서 모든 변수와 그 변수에 설정된 값을 출력합니다:
ctx: Context = copy_context() print(list(ctx.items()))
이 함수는 O(1) 복잡도를 갖고 있습니다. 즉, 몇 가지 컨텍스트 변수가 있는 컨텍스트와 컨텍스트 변수가 잔뜩 있는 컨텍스트에 대해 똑같이 빠르게 작동합니다.
- class contextvars.Context¶
ContextVars에서 그 값으로의 매핑.Context()는 값이 없는 빈 컨텍스트를 만듭니다. 현재 컨텍스트의 복사본을 얻으려면copy_context()함수를 사용하십시오.Each thread has its own effective stack of
Contextobjects. The current context is theContextobject at the top of the current thread’s stack. AllContextobjects in the stacks are considered to be entered.진입 하는 컨텍스트는, 해당
run()메서드를 호출하여 수행할 수 있으며, 이를 현재 스레드의 컨텍스트 스택 맨 위에 푸시하여 현재 컨텍스트를 만듭니다.만료 는 현재 컨텍스트를 종료하는 것으로,
run()메서드에 전달된 콜백에서 반환함으로써 수행되며, 컨텍스트 스택의 맨 위에서 컨텍스트를 제거하여 현재 컨텍스트를 이전 상태로 복원합니다.각 스레드는 자체 컨텍스트 스택을 가지므로,
ContextVar객체는 값을 서로 다른 스레드에서 할당할 때 :func:`threading.local`과 유사하게 동작합니다.이미 진입된 컨텍스트(다른 스레드에서 진입한 컨텍스트 포함)에 진입하려고 하면 :exc:`RuntimeError`가 발생합니다.
컨텍스트를 종료한 후에는 나중에 재진입될 수 있습니다 (어떤 스레드에서든).
ContextVar.set()메서드를 통해ContextVar값에 가해지는 모든 변경 사항은 현재 컨텍스트에 기록됩니다.ContextVar.get()메서드는 현재 컨텍스트와 관련된 값을 반환합니다. 컨텍스트를 종료하는 것은 컨텍스트가 진입된 동안 컨텍스트 변수에 가해진 모든 변경을 효과적으로 되돌립니다 (필요한 경우, 컨텍스트를 재진입하여 값을 복원할 수 있습니다).Context는
collections.abc.Mapping인터페이스를 구현합니다.- run(callable, *args, **kwargs)¶
컨텍스트에 진입하고,
callable(*args, **kwargs)를 실행한 다음, 컨텍스트에서 빠져나옵니다. callable의 반환값을 반환하거나, 예외가 발생하면 예외를 전파합니다.예제:
import contextvars var = contextvars.ContextVar('var') var.set('spam') print(var.get()) # 'spam' ctx = contextvars.copy_context() def main(): # 'var' 는 'copy_context()' 와 'ctx.run(main)' 을 # 호출하기 전에 'spam' 으로 설정되었습니다. 그래서: print(var.get()) # 'spam' print(ctx[var]) # 'spam' var.set('ham') # 이제, 'var' 를 'ham' 으로 설정한 후에: print(var.get()) # 'ham' print(ctx[var]) # 'ham' # 'main' 함수가 'var' 에 적용한 모든 변경은 'ctx' 에 포함됩니다. ctx.run(main) # 'main()' 함수는 'ctx' 컨텍스트에서 실행되었으므로, # 'var' 에 대한 변경은 'ctx' 에 포함되어 있습니다: print(ctx[var]) # 'ham' # 그러나, 'ctx' 외부에서, 'var' 는 여전히 'spam' 으로 설정되어있습니다: print(var.get()) # 'spam'
- copy()¶
컨텍스트 객체의 얕은 복사본을 반환합니다.
- var in context
context 에 var 의 값이 설정되었으면
True를, 그렇지 않으면 False를 반환합니다.
- context[var]
var
ContextVar변수의 값을 돌려줍니다. 컨텍스트 객체에 변수가 설정되어 있지 않으면KeyError가 발생합니다.
- get(var[, default])¶
컨텍스트 객체에 var 의 값이 있으면, var 의 값을 돌려줍니다. 그렇지 않으면 default 를 반환합니다. default 가 주어지지 않으면
None을 반환합니다.
- iter(context)
컨텍스트 객체에 저장된 변수에 대한 이터레이터를 반환합니다.
- len(proxy)
컨텍스트 객체에 설정된 변수의 개수를 반환합니다.
- keys()¶
컨텍스트 객체의 모든 변수 목록을 반환합니다.
- values()¶
컨텍스트 객체의 모든 변수의 값 목록을 반환합니다.
- items()¶
컨텍스트 객체에서 모든 변수와 해당 값을 포함하는 2-튜플의 목록을 반환합니다.
asyncio 지원¶
컨텍스트 변수는 asyncio 에서 기본적으로 지원되며 추가 구성없이 사용할 수 있습니다. 예를 들어, 이것은 컨텍스트 변수를 사용하여, 원격 클라이언트의 주소를 해당 클라이언트를 처리하는 Task에서 사용할 수 있도록 하는 간단한 메아리 서버입니다:
import asyncio
import contextvars
client_addr_var = contextvars.ContextVar('client_addr')
def render_goodbye():
# 현재 처리 중인 클라이언트를 이 함수에 명시적으로 전달하지 않고도
# 주소에 접근할 수 있습니다.
client_addr = client_addr_var.get()
return f'Good bye, client @ {client_addr}\\r\\n'.encode()
async def handle_request(reader, writer):
addr = writer.transport.get_extra_info('socket').getpeername()
client_addr_var.set(addr)
# 호출하는 모든 코드에서 이제 'client_addr_var.get()'을
# 호출하여 클라이언트의 주소를 얻는 것이 가능해졌습니다.
while True:
line = await reader.readline()
print(line)
if not line.strip():
break
writer.write(b'HTTP/1.1 200 OK\\r\\n') # status line
writer.write(b'\\r\\n') # headers
writer.write(render_goodbye()) # body
writer.close()
async def main():
srv = await asyncio.start_server(
handle_request, '127.0.0.1', 8081)
async with srv:
await srv.serve_forever()
asyncio.run(main())
# 테스트하려면 telnet이나 curl을 사용할 수 있습니다:
# telnet 127.0.0.1 8081
# curl 127.0.0.1:8081