Содржина на објавата
В асинхронных приложениях есть один не всегда очевидный момент, который приводит к неявным багам - это общие глобальные объекты. Да, это в целом антипаттерн, но иногда такие объекты действительно нужны и вполне уместны. Например, когда вы завязаны на уже существующем коде и не можете его поменять, но переменную подставлять надо, при этом явно пробросить её не получится. Для этого используется ContexctVar. Случаи бывают разные но я приведу самый понятный пример - логирование. Допустим, мы не можем передать id юзера куда-то внутрь фреймворка, но можем использовать его в своем хендлере подставляя как переменную. В примере будет без хендлера но суть та же. import asyncio from contextvars import ContextVar import random # это переменная, которая будет разной для каждой корутины user_id_ctx = ContextVar("user_id", default=-1) async def handle_request(user_name, user_id): # устанавливаем значение для текущей корутины и её дочерних корутин user_id_ctx.set(user_id) print(f"Create {user_name} == {user_id}") await asyncio.sleep(random.random()) # id не передаётся в вызов await process_order(user_name) async def process_order(user_name): # получаем значение из локального контекста current_user_id = user_id_ctx.get() print(f"Log {user_name}: {current_user_id}") async def main(): await asyncio.gather( *[handle_request(f"user {i}", i) for i in range(10)], ) if __name__ == "__main__": asyncio.run(main()) Во всех выводах id должен совпадать. - Точно так же можно подставлять атрибуты у инстансов синглтонов. - Контекст наследуется дочерними корутинами. - Не стоит увлекаться этим способом, он прилично усложняет логику. Явное лучше неявного. @asyncio@tricks