亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

生成器進(jìn)化到協(xié)程 Part 2

fuyi501 / 2810人閱讀

摘要:一個(gè)典型的上下文管理器類如下處理異常正如方法名明確告訴我們的,方法負(fù)責(zé)進(jìn)入上下的準(zhǔn)備工作,如果有需要可以返回一個(gè)值,這個(gè)值將會(huì)被賦值給中的??偨Y(jié)都是關(guān)于上下文管理器的內(nèi)容,與協(xié)程關(guān)系不大。

Part 1 傳送門

David Beazley 的博客

PPT 下載地址

在 Part 1 我們已經(jīng)介紹了生成器的定義和生成器的操作,現(xiàn)在讓我們開始使用生成器。Part 2 主要描述了如何使用 yieldcontextmanager 創(chuàng)建一個(gè)上下文管理器,并解釋了原理。


上下文管理器

理解上下文可以聯(lián)想我們做閱讀理解時(shí)要解讀文章某處的意思需要閱讀該處前后段落,正是前后文提供了理解的“背景”。而程序的運(yùn)行的上下文也可以理解為程序在運(yùn)行時(shí)的某些變量,正是這些變量構(gòu)成了運(yùn)行環(huán)境,讓程序可以完成操作。

Python 中的上下文管理器提供這樣一種功能,為你的程序運(yùn)行時(shí)提供一個(gè)特定“空間”,當(dāng)進(jìn)入這個(gè)空間時(shí) Python 上下文管理器 為你做一些準(zhǔn)備工作。這個(gè)“空間”中一般含有特殊的變量,你在這個(gè)“空間”中進(jìn)行一些操作,然后離開。在你離開時(shí) Python 上下文管理器又會(huì)幫你做一些收尾工作,保證不會(huì)污染運(yùn)行環(huán)境。

下面是一些常見(jiàn)的代碼模式

# 讀取文件
f = open()
# do something
f.close()


# 使用鎖
lock.acquire()
# do somethin
lock.release()


# 進(jìn)行數(shù)據(jù)庫(kù)操作
db.start_transaction()
# do something
db.commit()


# 對(duì)某段代碼進(jìn)行計(jì)時(shí)
start = time.time()
# do something
end = time.time()

這些代碼進(jìn)行的都是“先做這個(gè)(準(zhǔn)備工作,比如獲取一個(gè)數(shù)據(jù)庫(kù)連接),然后做這個(gè)(比如寫入數(shù)據(jù)),最后整理工作環(huán)境(如提交改動(dòng),關(guān)閉鏈接,釋放資源等)。

如果使用 with 可以這樣寫:

witn open(filename) as f:
    # do something
    pass
    
with lock():
    # do something
    pass

with 語(yǔ)句實(shí)際上使用了實(shí)現(xiàn)了 __enter____exit__ 方法的上下文管理器類。一個(gè)典型的上下文管理器類如下:

clss ContextManager:
    def __enter__(self):
        return value
    def __exit__(self, exc_type, val, tb):
        if exec_type is None:
            return
        else:
            # 處理異常
            return True if handled else False

正如方法名明確告訴我們的,__enter__ 方法負(fù)責(zé)進(jìn)入上下的準(zhǔn)備工作,如果有需要可以返回一個(gè)值,這個(gè)值將會(huì)被賦值給 with ContextManager() as ret_value 中的 ret_value 。__exit__ 則負(fù)責(zé)收尾工作,這包括了異常處理。

對(duì)于這樣一段代碼

with ContextManager() as var:
    # do something

相當(dāng)于

ctxmanager = ContextManager()
var = ctxmanager.__enter__()
# do somethin
ctxmanager.__exit__()

一個(gè)可用的例子:

import tempfile
import shutil

class TmpDir:
    def __enter__(self):
        self.dirname = tempfile.mkdtemp()
        return self.dirname
    
    def __exit__(self, exc, val, tb):
    shutil.rmtree(self.dirname)

這個(gè)上下文管理提供臨時(shí)文件的功能,在 with 語(yǔ)句結(jié)束后會(huì)自動(dòng)刪除臨時(shí)文件夾。

with TempDir() as dirname:
    # 使用臨時(shí)文件夾進(jìn)行一些操作
    pass

關(guān)于上面兩個(gè)特殊方法的文檔可以在 Python 文檔的 Context Manager Types 找到。另外關(guān)于 with 關(guān)鍵字的詳細(xì)說(shuō)明參考 PEP 343,不過(guò)這篇 PEP 不是很好讀,Good Luck :simple_smile:!

使用 yield 和 contextmanager

能看到這里的都應(yīng)該對(duì)上下文管理器有所了解,準(zhǔn)備好把 yield 加入我們的上下文管理器代碼中。

先看一個(gè)例子

import tempfile, shutil
from contextlib import contextmanager

@contextmanager
def tempdir():
    outdir = tempfile.mkdtemp()
    try:
        yield outdir
    finally:
        shutil.rmtree(outdir)

與使用上下文管理器類的實(shí)現(xiàn)方式不同,這里我們沒(méi)有顯式實(shí)現(xiàn) __enter____exit__,而是通過(guò) contextmanager 裝飾器和 yield 實(shí)現(xiàn),你可以試試這兩種方式是等價(jià)的。

要理解上面的代碼,可以把 yield 想象為一把剪刀,把這個(gè)函數(shù)一分為二,上部分相當(dāng)于 __enter__,下部分相當(dāng)于 __exit__。我這樣說(shuō)大家應(yīng)該明白了吧。

import tempfile, shutil
from contextlib import contextmanager

@contextmanager
def tempdir():
    outdir = tempfile.mkdtemp() #
    try:                        # __enter__
        yield outdir            #
--cut---╳-----------------------------------
    finally:                    #
        shutil.rmtree(outdir)   # __exit__

實(shí)現(xiàn)“剪刀”功能關(guān)鍵在于 contextmanager 。對(duì)于上面的代碼,我們來(lái)一步一步地結(jié)構(gòu)它:

contextmanager 裝飾器

contextmanager 其實(shí)使用了一個(gè)上下文管理器類,這個(gè)類在在初始化時(shí)需要提供一個(gè)生成器。

class GeneratorCM:
    def __init__(self, gen):
        self.gen = gen
    
    def __enter__(self):
       ...
        
    def __exit__(self, exc, val, tb):
        ...

contextmanager 的實(shí)現(xiàn)如下

def contextmanager(func):
    def run(*args, **kwargs):
        return GeneratorCM(func(*args, **kwargs))
    return run

由于 contextmanger 所裝飾的函數(shù)里有 yield 所以我們?cè)谡{(diào)用 func(*args, **kwargs) 時(shí)返回的是一個(gè)生成器。要使這個(gè)生成器前進(jìn),我們需要調(diào)用 next 函數(shù)

讓生成器前進(jìn)
def __enter__(self):
    return next(self.gen)

GeneratorCM__ente__ 方法會(huì)讓生成器前進(jìn)到 yield 語(yǔ)句處,并返回產(chǎn)出值。

收尾
def __exit__(self, exc, val, tb):
    try:
        if exc is None:
            next(self.gen)
        else:
            self.gen.throw(exc, val, tb)
        raise RuntimeError("Generator didn"t stop")
    except StopIteration:
        return True
    except:
        if sys.exc_info()[1] is not val: raise

__exit__ 函數(shù)的邏輯比較復(fù)雜,如果沒(méi)有傳入異常,首先它會(huì)嘗試對(duì)生成器調(diào)用 next,正常情況下這會(huì)拋出 StopIteration ,這個(gè)異常會(huì)被不做并返回 True ,告訴解釋器正常退出;如果傳入異常,會(huì)使用 throwyield 處拋出這個(gè)異常;如果有其他未捕捉的錯(cuò)誤,就重新拋出該錯(cuò)誤。

實(shí)際的代碼實(shí)現(xiàn)會(huì)更加復(fù)雜,還有一些異常情況沒(méi)有處理

沒(méi)有相關(guān)值的異常

在 with 語(yǔ)句塊中拋出的 StopIteration

在上下文管理器中拋出的異常

如果你對(duì)怎么實(shí)現(xiàn)感興趣,你可以閱讀代碼或者再一次閱讀 PEP 343。

總結(jié)

Part 2 都是關(guān)于上下文管理器的內(nèi)容,與協(xié)程關(guān)系不大。但通過(guò)這部分我們可以看到 yield 完全不同的用法,也熟悉了控制流 (control-flow) ,這與 Part 3 的異步處理流程有很大關(guān)系。讓我們 Part 3 再見(jiàn)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/41947.html

相關(guān)文章

  • 成器進(jìn)化協(xié)程 Part 1

    摘要:生成器用于定義生成器函數(shù)只要存在該函數(shù)必定是一個(gè)生成器調(diào)用該函數(shù)返回一個(gè)生成器讓一個(gè)生成器前進(jìn)使用使一個(gè)生成器前進(jìn)到下一個(gè)語(yǔ)句處,并將產(chǎn)出值作為其返回值。 前言 這篇文章大部分來(lái)自 David Beazley 在 PyCon 2014 的 PPT 《Generators: The Final Frontier》。這個(gè)PPT很長(zhǎng)而且非常燒腦,建議在閱讀前應(yīng)了解 Python 的生成器與攜...

    lemon 評(píng)論0 收藏0
  • PHP回顧之協(xié)程

    摘要:本文先回顧生成器,然后過(guò)渡到協(xié)程編程。其作用主要體現(xiàn)在三個(gè)方面數(shù)據(jù)生成生產(chǎn)者,通過(guò)返回?cái)?shù)據(jù)數(shù)據(jù)消費(fèi)消費(fèi)者,消費(fèi)傳來(lái)的數(shù)據(jù)實(shí)現(xiàn)協(xié)程。解決回調(diào)地獄的方式主要有兩種和協(xié)程。重點(diǎn)應(yīng)當(dāng)關(guān)注控制權(quán)轉(zhuǎn)讓的時(shí)機(jī),以及協(xié)程的運(yùn)作方式。 轉(zhuǎn)載請(qǐng)注明文章出處: https://tlanyan.me/php-review... PHP回顧系列目錄 PHP基礎(chǔ) web請(qǐng)求 cookie web響應(yīng) sess...

    Java3y 評(píng)論0 收藏0
  • tornado 源碼之 coroutine 分析

    摘要:源碼之分析的協(xié)程原理分析版本為支持異步,實(shí)現(xiàn)了一個(gè)協(xié)程庫(kù)。提供了回調(diào)函數(shù)注冊(cè)當(dāng)異步事件完成后,調(diào)用注冊(cè)的回調(diào)中間結(jié)果保存結(jié)束結(jié)果返回等功能注冊(cè)回調(diào)函數(shù),當(dāng)被解決時(shí),改回調(diào)函數(shù)被調(diào)用。相當(dāng)于喚醒已經(jīng)處于狀態(tài)的父協(xié)程,通過(guò)回調(diào)函數(shù),再執(zhí)行。 tornado 源碼之 coroutine 分析 tornado 的協(xié)程原理分析 版本:4.3.0 為支持異步,tornado 實(shí)現(xiàn)了一個(gè)協(xié)程庫(kù)。 ...

    NicolasHe 評(píng)論0 收藏0
  • PyTips 0x13 - Python 線程與協(xié)程2

    摘要:項(xiàng)目地址我之前翻譯了協(xié)程原理這篇文章之后嘗試用了模式下的協(xié)程進(jìn)行異步開發(fā),確實(shí)感受到協(xié)程所帶來(lái)的好處至少是語(yǔ)法上的。 項(xiàng)目地址:https://git.io/pytips 我之前翻譯了Python 3.5 協(xié)程原理這篇文章之后嘗試用了 Tornado + Motor 模式下的協(xié)程進(jìn)行異步開發(fā),確實(shí)感受到協(xié)程所帶來(lái)的好處(至少是語(yǔ)法上的:D)。至于協(xié)程的 async/await 語(yǔ)法是如...

    史占廣 評(píng)論0 收藏0
  • 圖文 視頻雙管齊下,帶你全面徹底理解Retrofit源碼,Android開發(fā)五年

    摘要:協(xié)程的判斷條件下面我們來(lái)著重看下的源碼,因?yàn)閺倪@里開始就涉及到協(xié)程的判斷。第二點(diǎn)是關(guān)鍵點(diǎn),用來(lái)判斷該方法的調(diào)用是否使用到了協(xié)程。原理我們先來(lái)看下使用協(xié)程是怎么寫的這是一個(gè)標(biāo)準(zhǔn)的協(xié)程寫法,然后我們?cè)偬子蒙厦娴臈l件,發(fā)現(xiàn)完全匹配不到。 第一眼看,跟我之前印象中的有點(diǎn)區(qū)別(也不知道是什么版本),return的時(shí)候居然...

    不知名網(wǎng)友 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<