Python利用contextvars實現(xiàn)管理上下文變量_第1頁
Python利用contextvars實現(xiàn)管理上下文變量_第2頁
Python利用contextvars實現(xiàn)管理上下文變量_第3頁
Python利用contextvars實現(xiàn)管理上下文變量_第4頁
Python利用contextvars實現(xiàn)管理上下文變量_第5頁
已閱讀5頁,還剩3頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第Python利用contextvars實現(xiàn)管理上下文變量"""

先awaitget2()得到的就是set_函數(shù)中設置的值,這是符合預期的。但是我們在get1中將值重新設置了,那么之后不管是awaitget1()還是直接awaitget2(),得到的都是新設置的值。

這也說明了,一個協(xié)程內部await另一個協(xié)程,另一個協(xié)程內部await另另一個協(xié)程,不管套娃(await)多少次,它們獲取的值都是一樣的。并且在任意一個協(xié)程內部都可以重新設置值,然后獲取會得到最后一次設置的值。再舉個栗子:

import

asyncio

import

contextvars

c

=

contextvars.ContextVar("只是一個標識,

用于調試")

async

def

get1():

return

await

get2()

async

def

get2():

val

=

c.get()

+

"~~~"

c.set("重新設置啦")

return

val

async

def

set_(val):

#

設置值

c.set(val)

print(await

get1())

print(c.get())

async

def

main():

coro

=

set_("古明地覺")

await

coro

asyncio.run(main())

古明地覺~~~

重新設置啦

"""

awaitget1()的時候會執(zhí)行awaitget2(),然后在里面拿到c.set設置的值,打印古明地覺~~~。但是在get2里面,又將值重新設置了,所以第二個print打印的就是新設置的值。\

如果在get之前沒有先set,那么會拋出一個LookupError,所以ContextVar支持默認值:

import

asyncio

import

contextvars

c

=

contextvars.ContextVar("只是一個標識,

用于調試",

default="哼哼")

async

def

set_(val):

print(c.get())

c.set(val)

print(c.get())

async

def

main():

coro

=

set_("古明地覺")

await

coro

asyncio.run(main())

"""

除了在ContextVar中指定默認值之外,也可以在get中指定:

import

asyncio

import

contextvars

c

=

contextvars.ContextVar("只是一個標識,

用于調試",

default="哼哼")

async

def

set_(val):

print(c.get("古明地戀"))

c.set(val)

print(c.get())

async

def

main():

coro

=

set_("古明地覺")

await

coro

asyncio.run(main())

"""

所以結論如下,如果在c.set之前使用c.get:

當ContextVar和get中都沒有指定默認值,會拋出LookupError;只要有一方設置了,那么會得到默認值;如果都設置了,那么以get為準;

如果c.get之前執(zhí)行了c.set,那么無論ContextVar和get有沒有指定默認值,獲取到的都是c.set設置的值。

所以總的來說還是比較好理解的,并且ContextVar除了可以作用在協(xié)程上面,它也可以用在線程上面。沒錯,它可以替代threading.local,我們來試一下:

import

threading

import

contextvars

c

=

contextvars.ContextVar("context_var")

def

get():

name

=

threading.current_thread().name

value

=

c.get()

print(f"線程

{name},

value:

{value}")

def

set_():

name

=

threading.current_thread().name

if

name

==

"one":

c.set("ONE")

elif

name

==

"two":

c.set("TWO")

get()

t1

=

threading.Thread(target=set_,

name="one")

t2

=

threading.Thread(target=set_,

name="two")

t1.start()

t2.start()

線程

one,

value:

ONE

線程

two,

value:

TWO

"""

和threading.local的表現(xiàn)是一樣的,但是更建議使用ContextVars。不過前者可以綁定任意多個值,而后者只能綁定一個值(可以通過傳遞字典的方式解決這一點)。

c.Token

當我們調用c.set的時候,其實會返回一個Token對象:

import

contextvars

c

=

contextvars.ContextVar("context_var")

token

=

c.set("val")

print(token)

Token

var=ContextVar

name='context_var'

at

0x00..

at

0x00...

"""

Token對象有一個var屬性,它是只讀的,會返回指向此token的ContextVar對象。

import

contextvars

c

=

contextvars.ContextVar("context_var")

token

=

c.set("val")

print(token.var

is

c)

#

True

print(token.var.get())

#

val

print(

token.var.set("val2").var.set("val3").var

is

c

)#

True

print(c.get())

#

val3

Token對象還有一個old_value屬性,它會返回上一次set設置的值,如果是第一次set,那么會返回一個Token.MISSING。

import

contextvars

c

=

contextvars.ContextVar("context_var")

token

=

c.set("val")

#

token

是第一次

c.set

所返回的

#

在此之前沒有

set,所以

old_value

Token.MISSING

print(token.old_value)

#

Token.MISSING

token

=

c.set("val2")

print(c.get())

#

val2

#

返回上一次

set

的值

print(token.old_value)

#

val

那么這個Token對象有什么作用呢?從目前來看貌似沒太大用處啊,其實它最大的用處就是和reset搭配使用,可以對狀態(tài)進行重置。

import

contextvars

####

c

=

contextvars.ContextVar("context_var")

token

=

c.set("val")

#

顯然是可以獲取的

print(c.get())

#

val

#

將其重置為

token

之前的狀態(tài)

#

但這個

token

是第一次

set

返回的

#

那么之前就相當于沒有

set

c.reset(token)

c.get()

#

此時就會報錯

except

LookupError:

print("報錯啦")

#

報錯啦

#

但是我們可以指定默認值

print(c.get("默認值"))

#

默認值

contextvars.Context

它負責保存ContextVars對象和設置的值之間的映射,但是我們不會直接通過contextvars.Context來創(chuàng)建,而是通過contentvars.copy_context函數(shù)來創(chuàng)建。

import

contextvars

c1

=

contextvars.ContextVar("context_var1")

c1.set("val1")

c2

=

contextvars.ContextVar("context_var2")

c2.set("val2")

#

此時得到的是所有

ContextVar

對象和設置的值之間的映射

#

它實現(xiàn)了

collections.abc.Mapping

接口

#

因此我們可以像操作字典一樣操作它

context

=

contextvars.copy_context()

#

key

就是對應的

ContextVar

對象,value

就是設置的值

print(context[c1])

#

val1

print(context[c2])

#

val2

for

ctx,

value

in

context.items():

print(ctx.get(),

,

value)

"""

val1

context_var1

val1

val2

context_var2

val2

"""

print(len(context))

#

2

除此之外,context還有一個run方法:

import

contextvars

c1

=

contextvars.ContextVar("context_var1")

c1.set("val1")

c2

=

contextvars.ContextVar("context_var2")

c2.set("val2")

context

=

contextvars.copy_context()

def

change(val1,

val2):

c1.set(val1)

c2.set(val2)

print(c1.get(),

context[c1])

print(c2.get(),

context[c2])

#

change

函數(shù)內部,重新設置值

#

然后里面打印的也是新設置的值

context.run(change,

"VAL1",

"VAL2")

VAL1

VAL1

VAL2

VAL2

print(c1.get(),

context[c1])

print(c2.get(),

context[c2])

val1

VAL1

val2

VAL2

"""

我們看到run方法接收一個callable,如果在里面修改了ContextVar實例設置的值,那么對于ContextVar而言只會在函數(shù)內部生效,一旦出了函數(shù),那么還是原來的值。但是對于Context而言,它是會受到影響的,即便出了函數(shù),也是新設置的值,因為它直接把內部的字典給修改了。

小結

以上就是contextvars模塊的用法,在多個協(xié)程之間傳遞數(shù)據(jù)是非常方便的,并且也是并發(fā)安全的。如果你用過Go的話,你

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論