Python3.7 contextvars 初探

简述

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

KeyContextVar

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->ValueMapping。在不同的上下文中,同一个上下文变量的值可以不同。

如果作用域中没有ContextVar,你是无法访问或修改ContextVar的,文档中建议在模块级别定义ContextVar也是这个原因。

Q & A Q:定义ContextVar时发生了什么?

A:新建了一个对象,仅此而已,上下文中没有保存它。当ContextVar被set后,上下文中才会有它。

Q:访问或修改ContextVar时发生了什么?

A:访问ContextVar时,实际上是在当前上下文中查表,返回当前上下文中ContextVar的值。修改同理,实际上是改表。(在源码中还有cache,这里不作说明)

Q:Context机制如何实现?

A:Context与ThreadState相关,进入上下文时“占据”当前线程,退出时“放弃”当前线程。

四、总结

contextvars为异步而生,上下文对象将简化asyncio的复杂操作,给异步程序的编写带来方便,推荐高级玩家使用。

原文发布于微信公众号 - Python中文社区(python-china)

原文发表时间:2018-10-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏乐百川的学习频道

设计模式(二十三) 模板模式

模板模式也是一种行为型模式,而且它非常好理解。当我们解决问题需要固定几个步骤, 这些步骤的顺序不能改变,而步骤的具体实现可以变化的时候,就可以使用模板模式。模板...

17760
来自专栏python3

习题25:布尔表达式练习

在编程中,布尔逻辑可以说是无处不在,它们是计算机运算的基础和重要组成部分,掌握它们很重要!

8720
来自专栏iOSDevLog

How do you compare two version Strings in Java?

https://stackoverflow.com/questions/198431/how-do-you-compare-two-version-string...

11740
来自专栏Java技术栈

volatile关键字解析~高级java必问

昨天我介绍了原子性、可见性、有序性的概念,那么今天就来见识下这些概念的主角-volatile关键字。 volatile基本介绍 volatile可以看成是syn...

28860
来自专栏快乐八哥

JSON入门指南--客户端处理JSON

在传统的Web开发过程中,前端工程师或者后台工程师会在页面上写后台的相关代码,比如在ASP.NET MVC4里面写如下代码: @Html.TextBoxFor(...

24560
来自专栏用户2442861的专栏

《Java虚拟机原理图解》 1.1、class文件基本组织结构

http://blog.csdn.net/luanlouis/article/details/39892027

12120
来自专栏IMWeb前端团队

Nodejs进阶:服务端字符编解码&乱码处理

本文作者:IMWeb 陈映平 原文出处:IMWeb社区 未经同意,禁止转载 写在前面 在web服务端开发中,字符的编解码几乎每天都要打交道。编解码一旦...

438100
来自专栏向治洪

java基础Haep(堆)和Stack(栈)区别

简单的可以理解为: heap:是由malloc之类函数分配的空间所在地。地址是由低向高增长的。  stack:是自动分配变量,以及函数调用的时候所使用的一些空...

22970
来自专栏Java成长之路

五、Java对象的访问定位

Java对象在访问的时候,我们需要通过java虚拟机栈的reference类型的数据去操作具体的对象。由于reference类型在java虚拟机规范中只规定了一...

22120
来自专栏黑泽君的专栏

动态代理详解

动态代理它可以直接给某一个目标对象生成一个代理对象,而不需要代理类存在。     动态代理与代理模式原理是一样的,只是它没有具体的代理类,直接通过反射生成了一...

9520

扫码关注云+社区

领取腾讯云代金券