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的複雜操作,給異步程序的編寫帶來方便,推薦高級玩家使用。


原文發佈時間爲:2018-10-14

本文作者:Nugine

本文來自雲棲社區合作伙伴“Python中文社區”,瞭解相關信息可以關注“Python中文社區”。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章