簡述
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中文社區”。