简述
Python 3.7 于2018年6月27日发布,本篇文章将对其中新增模块contextvars 做初步介绍,为读者勾勒一个大概轮廓。
资料来源: Python 3.7 文档、源码。
1、contextvars是什么
2、类与方法
3、如何理解上下文
4、总结
一、contextvars是什么
这个模块提供了一组接口,可用于管理、储存、访问 局部上下文的状态。
主要用于在异步环境中管理上下文变量。
二、类与方法
1、ContextVar(name[, *, default])
这个类用于表示一个上下文变量。
参数:name
: 必要位参; 用于检验和Debug.
default
: 默参,且只能用keyword方式指定; 用于设定这个上下文变量的默认值。
属性:name
:只读特性。
get([default])
:返回该上下文变量的值。未指定默认值且上下文变量无默认值时,抛出LookupError
。
set(value)
:设置上下文变量的值,返回一个与变量当前值相关的Token对象,可用于重置上下文变量的值到该次set之前。
reset(token)
:使用token重置上下文变量的值。
示例:
from contextvars import *
var= ContextVar('var')
x=[1]
var.set(x)
y=var.get()
print(f'x: {id(x)},y: {id(y)},{id(x)==id(y)}')
y=var.get()
print(f'x: {id(x)},y: {id(y)},{id(x)==id(y)}')
z=[2]
token=var.set(z)
print(f'z: {var.get()}')
var.reset(token)
y=var.get()
print(f'x: {id(x)},y: {id(y)},{id(x)==id(y)}')
输出:
x: 2459227742792,y: 2459227742792,True
x: 2459227742792,y: 2459227742792,True
z: [2]
x: 2459227742792,y: 2459227742792,True
2、Token
属性:var
: 只读特性,指向创建它的上下文变量。
old_value
: 只读特性,保存set之前的上下文变量的值。如果值为空,该特性指向Token.MISSING
.
3、Context
类型:Mapping
Key
:ContextVar
Value
:上下文变量的值
属性:copy()
:返回Context
的浅拷贝。
run(callable, *args, **kwargs)
:在该上下文中运行callable(args, *kwargs)
.
当多线程同时执行run
时,抛出RuntimeError
.
当递归地执行run
时,也会抛出RuntimeError
.
同一个Context
,在同一时刻只能有一个run
方法运行。
PS:多进程显然不在考虑范围内。
文档示例:
var = ContextVar('var')
var.set('spam')
def main():
# 'var' was set to 'spam' before
# calling 'copy_context()' and 'ctx.run(main)', so:
# var.get() == ctx[var] == 'spam'
var.set('ham')
# Now, after setting 'var' to 'ham':
# var.get() == ctx[var] == 'ham'
ctx = copy_context()
# Any changes that the 'main' function makes to 'var'
# will be contained in 'ctx'.
ctx.run(main)
# The 'main()' function was run in the 'ctx' context,
# so changes to 'var' are contained in it:
# ctx[var] == 'ham'
# However, outside of 'ctx', 'var' is still set to 'spam':
# var.get() == 'spam'
4、模块方法:copy_context()
返回当前上下文的拷贝。
时间复杂度: O(1)。因为在C源码中,这个函数只做了新建对象和指针复制。
不管当前上下文有多臃肿,copy_context()
的消耗都是不变的。
三、如何理解上下文
自己动手写一些小程序试验一下是最好的方法。
这里给出我的理解:
作用域规定了对象访问权,而上下文规定了上下文变量值访问权。
我们用ContextVar
表示上下文变量,而具体的值存储在Context
中。所以Context
实现为ContextVar->Value
的Mapping
。在不同的上下文中,同一个上下文变量的值可以不同。
如果作用域中没有ContextVar
,你是无法访问或修改ContextVar
的,文档中建议在模块级别定义ContextVar
也是这个原因。
Q & A
Q:定义ContextVar
时发生了什么?
A:新建了一个对象,仅此而已,上下文中没有保存它。当ContextVar
被set后,上下文中才会有它。
Q:访问或修改ContextVar
时发生了什么?
A:访问ContextVar
时,实际上是在当前上下文中查表,返回当前上下文中ContextVar
的值。修改同理,实际上是改表。(在源码中还有cache,这里不作说明)
Q:Context机制如何实现?
A:Context与ThreadState相关,进入上下文时“占据”当前线程,退出时“放弃”当前线程。
四、总结
contextvars为异步而生,上下文对象将简化asyncio的复杂操作,给异步程序的编写带来方便,推荐高级玩家使用。
原文发布时间为:2018-10-14
本文作者:Nugine
本文来自云栖社区合作伙伴“Python中文社区”,了解相关信息可以关注“Python中文社区”。