python3.6 使用调用栈储存上下文变量

python3.6 使用调用栈储存上下文变量

从 python3.7 开始, 新增 contextvars 模块, 用于储存上下文变量.

使用场景

# python3.7
from contextvars import ContextVar
import asyncio

user = ContextVar('var')


async def b():
    u = user.get()
    print(f'get name {u}')


async def a(name):
    user.set(name)
    print(f'set name {name}')
    await asyncio.sleep(0.1)
    print('after sleep 0.1s')
    await b()


async def main():
    await asyncio.gather(a('foo'), a('bar'))


if __name__ == "__main__":
    asyncio.run(main())

"""
# output:

set name foo
set name bar
after sleep 0.1s
get name foo
after sleep 0.1s
get name bar
"""

python3.6 实现相似功能

思路

  • 在一个函数中可以获取当前调用栈;
  • 从当前调用栈可以访问上一级调用栈;
  • 调用栈是一个 PyObject 对象, 可以动态添加数据;

实现

# python3.6
import asyncio

import inspect
import logging


def get_context(symbol):
    f = inspect.currentframe()
    while f:
        value = f.f_locals.get(symbol)
        if value:
            return value
        f = f.f_back
    return ''


def set_context(symbol, value, stack_deepth=1):
    f = inspect.currentframe()
    for _ in range(stack_deepth):
        f = f.f_back
    f.f_locals[symbol] = value


USER_SYMBOL = 'USER'


def get_user():
    return get_context(USER_SYMBOL)


def set_user(value, stack_deepth=1):
    return set_context(USER_SYMBOL, value, stack_deepth=stack_deepth+1)


async def b():
    u = get_user()
    print(f'get name {u}')


async def a(name):
    set_user(name)
    print(f'set name {name}')
    await asyncio.sleep(0.1)
    print('after sleep 0.1s')
    await b()


async def main():
    await asyncio.gather(a('foo'), a('bar'))


if __name__ == "__main__":
    l = asyncio.get_event_loop()
    l.run_until_complete(main())

"""
# output:

set name foo
set name bar
after sleep 0.1s
get name foo
after sleep 0.1s
get name bar
"""
posted @ 2024-03-25 11:54  Aloe_n  阅读(9)  评论(0编辑  收藏  举报