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
"""