国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

《Python有什么好學(xué)的》之上下文管理器

qpwoeiru96 / 1647人閱讀

摘要:引上下文管理器太極生兩儀,兩儀為陰陽(yáng)。而最常用的則是,即上下文管理器使用上下文管理器用之后的文件讀寫(xiě)會(huì)變成我們看到用了之后,代碼沒(méi)有了創(chuàng)建,也沒(méi)有了釋放。實(shí)現(xiàn)上下文管理器我們先感性地對(duì)進(jìn)行猜測(cè)。現(xiàn)實(shí)一個(gè)上下文管理器就是這么簡(jiǎn)單。

“Python有什么好學(xué)的”這句話可不是反問(wèn)句,而是問(wèn)句哦。

主要是煎魚(yú)覺(jué)得太多的人覺(jué)得Python的語(yǔ)法較為簡(jiǎn)單,寫(xiě)出來(lái)的代碼只要符合邏輯,不需要太多的學(xué)習(xí)即可,即可從一門其他語(yǔ)言跳來(lái)用Python寫(xiě)(當(dāng)然這樣是好事,誰(shuí)都希望入門簡(jiǎn)單)。

于是我便記錄一下,如果要學(xué)Python的話,到底有什么好學(xué)的。記錄一下Python有什么值得學(xué)的,對(duì)比其他語(yǔ)言有什么特別的地方,有什么樣的代碼寫(xiě)出來(lái)更Pythonic。一路回味,一路學(xué)習(xí)。

引上下文管理器

太極生兩儀,兩儀為陰陽(yáng)。

道有陰陽(yáng),月有陰晴,人有生死,門有開(kāi)關(guān)。

你看這個(gè)門,它能開(kāi)能關(guān),就像這個(gè)對(duì)象,它能創(chuàng)建能釋放。(扯遠(yuǎn)了

編程這行,幾十年來(lái)都繞不開(kāi)內(nèi)存泄露這個(gè)問(wèn)題。內(nèi)存泄露的根本原因,就是把某個(gè)對(duì)象創(chuàng)建了,但是卻沒(méi)有去釋放它。直到程序結(jié)束前那一刻,這個(gè)未被釋放的對(duì)象還一直占著內(nèi)存,即使程序已經(jīng)不用這個(gè)對(duì)象了。泄露的量少的話還好,量大的話就直接打滿內(nèi)存,然后程序就被kill了。

聰明的程序員經(jīng)過(guò)了這十幾年的努力,創(chuàng)造出很多高級(jí)編程語(yǔ)言,這些編程語(yǔ)言已經(jīng)不再需要讓程序員過(guò)度關(guān)注內(nèi)存的問(wèn)題了。但是在編程時(shí),一些常見(jiàn)的對(duì)象釋放、流關(guān)閉還是要程序員顯式地寫(xiě)出來(lái)。

最常見(jiàn)的就是文件操作了。

常見(jiàn)的文件操作方式

原始的Python文件操作方式,很簡(jiǎn)單,也很common(也很java):

def read_file_1():
    f = open("file_demo.py", "r")
    try:
        print(f.read())
    except Exception as e:
        pass
    f.close()

就是這么簡(jiǎn)簡(jiǎn)單單的,先open然后讀寫(xiě)再close,中間讀寫(xiě)加個(gè)異常處理。

其中close就是釋放資源了,在這里如果不close,可能:

資源不釋放,直到不可控的垃圾回收來(lái)了,甚至直到程序結(jié)束

中間對(duì)文件修改時(shí),修改的信息還沒(méi)來(lái)得及寫(xiě)入文件

整個(gè)代碼顯得不規(guī)范

因此寫(xiě)上close函數(shù)理論上已經(jīng)必須的了,可是xxx.close()這樣寫(xiě)上去,在邏輯復(fù)雜的時(shí)候讓人容易遺漏,同時(shí)也顯得不雅觀。

這時(shí),各種語(yǔ)言生態(tài)有各種解決方案。

像Java,就直接jvm+依賴注入,直接把對(duì)象的生命周期管理接管了,只留下對(duì)象的使用功能給程序員;像golang,defer一下就好。而python最常用的則是with,即上下文管理器

使用上下文管理器

用with之后的文件讀寫(xiě)會(huì)變成:

def read_file_2():
    with open("file_demo.py", "r") as f:
        print(f.read())

我們看到用了with之后,代碼沒(méi)有了open創(chuàng)建,也沒(méi)有了close釋放。而且也沒(méi)有了異常處理,這樣子我們一看到代碼,難免會(huì)懷疑它的健壯性。

為了更好地理解上下文管理器,我們先實(shí)現(xiàn)試試。

實(shí)現(xiàn)上下文管理器

我們先感性地對(duì)with進(jìn)行猜測(cè)。

從調(diào)用with的形式上看,with像是一個(gè)函數(shù),包裹住了open和close:

# 大概意思而已 with = open + do + close
def with():
    open(xxxx)
    doSomething(xxxx)
    close(xxxx)

而Python的庫(kù)中已有的方案(contextmanager)也和上面的偽代碼具有一定的相似性:

from contextlib import contextmanager

@contextmanager
def c(s):
    print(s + "start")
    yield s
    print(s + "end")

“打印start”相當(dāng)于open,而“打印end”相當(dāng)于close,yield語(yǔ)法和修飾器(@)不熟悉的同學(xué)可以復(fù)習(xí)一下這些文章:生成器和修飾器。

然后我們調(diào)用這個(gè)上下文管理器試試,注意煎魚(yú)還給上下文管理器加了參數(shù)s,輸出的時(shí)候會(huì)帶上:

def test_context():
    with c("123") as cc:
        print("in with")
        print(type(cc))

if __name__ == "__main__":
    test_context()

我們看到,start和end前都有實(shí)參s=123。

現(xiàn)實(shí)一個(gè)上下文管理器就是這么簡(jiǎn)單。

異常處理

但是我們必須要注重異常處理,假如上面的上下文管理器中拋異常了怎么辦呢:

def test_context():
    with c("123") as cc:
        print("in with")
        print(type(cc))
        raise Exception

結(jié)果:

顯然,這樣弱雞的異常處理,煎魚(yú)時(shí)忍不了的。而且最重要的是,后面的close釋放居然沒(méi)有執(zhí)行!

我們可以在實(shí)現(xiàn)上下管理器時(shí),接入異常處理:

@contextmanager
def c():
    print("start")
    try:
        yield
    finally:
        print("end")
        
def test_except():
    try:
        with c() as cc:
            print("in with")
            raise Exception

    except:
        print("catch except")

調(diào)用test_except函數(shù)輸出:

我們?cè)谏舷挛墓芾砥鞯膶?shí)現(xiàn)中加入了try-finally,保證出現(xiàn)異常的時(shí)候,上下文管理器也能執(zhí)行close。同時(shí)在調(diào)用with前也加入try結(jié)構(gòu),保證整個(gè)函數(shù)的正常運(yùn)行。

然而,加入了這些東西之后,整個(gè)函數(shù)變得復(fù)雜又難看。

因此,煎魚(yú)覺(jué)得,想要代碼好看,抽象的邏輯需要再次升華,即從函數(shù)的層面升為對(duì)象(類)的層面。

實(shí)現(xiàn)上下文管理器類

其實(shí)用類實(shí)現(xiàn)上下文管理器,從邏輯理解上簡(jiǎn)單了很多,而且不需要引入那一個(gè)庫(kù):

class ContextClass(object):
    def __init__(self, s):
        self.s = s

    def __enter__(self):
        print(self.s + "call enter")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(self.s + "call exit")

    def test(self):
        print(self.s + "call test")

從代碼的字面意思上,我們就能感受得出來(lái),__enter__即為我們理解的open函數(shù),__exit__就是close函數(shù)。

接下來(lái),我們調(diào)用一下這個(gè)上下文管理器:

def test_context():
    with ContextClass("123") as c:
        print("in with")
        c.test()
        print(type(c))
        print(isinstance(c, ContextClass))

    print("")
    c = ContextClass("123")
    print(type(c))
    print(isinstance(c, ContextClass))

if __name__ == "__main__":
    test_context()

輸出結(jié)果:

功能上和直接用修飾器一致,只是在實(shí)現(xiàn)的過(guò)程中,邏輯更清晰了。

異常處理

回到我們?cè)瓉?lái)的話題:異常處理。

直接用修飾器實(shí)現(xiàn)的上下文管理器處理異常時(shí)可以說(shuō)是很難看了,那么我們的類選手表現(xiàn)又如何呢?

為了方便比較,煎魚(yú)把未進(jìn)行異常處理的和已進(jìn)行異常處理的一起寫(xiě)出來(lái),然后煎魚(yú)調(diào)用一個(gè)不存在的方法來(lái)拋異常:

class ContextClass(object):
    def __init__(self, s):
        self.s = s

    def __enter__(self):
        print(self.s + "call enter")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(self.s + "call exit")

class ContextExceptionClass(object):
    def __init__(self, s):
        self.s = s

    def __enter__(self):
        print(self.s + "call enter")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(self.s + "call exit")
        return True
        
def test_context():
    with ContextExceptionClass("123") as c:
        print("in with")
        t = c.test()
        print(type(t))

    # with ContextClass("456") as c:
        # print("in with")
        # t = c.test()
        # print(type(t))

if __name__ == "__main__":
    test_context()

輸出不一樣的結(jié)果:

結(jié)果發(fā)現(xiàn),看了半天,兩個(gè)類只有最后一句不一樣:異常處理的類中__exit__函數(shù)多一句返回,而且還是return了True。

而且這兩個(gè)類都完成了open和close兩部,即使后者拋異常了。

而在__exit__中加return True的意思就是不把異常拋出。

如果想要詳細(xì)地處理異常,而不是像上面治標(biāo)不治本的隱藏異常,則需要在__exit__函數(shù)中處理異常即可,因?yàn)樵摵瘮?shù)中有著異常的信息。

不信?稍微再改改:

class ContextExceptionClass(object):
    def __init__(self, s):
        self.s = s

    def __enter__(self):
        print(self.s + "call enter")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(self.s + "call exit")
        print(str(exc_type) + " " + str(exc_val) + " " + str(exc_tb))
        return True

輸出與預(yù)期異常信息一致:

先這樣吧

若有錯(cuò)誤之處請(qǐng)指出,更多地請(qǐng)關(guān)注造殼。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/45020.html

相關(guān)文章

  • Python什么好學(xué)修飾

    摘要:然后煎魚(yú)加了一個(gè)后再調(diào)用函數(shù),得到的輸出結(jié)果和加修飾器的一樣,換言之等效于因此,我們對(duì)于,可以理解是,它通過(guò)閉包的方式把新函數(shù)的引用賦值給了原來(lái)函數(shù)的引用。 Python有什么好學(xué)的這句話可不是反問(wèn)句,而是問(wèn)句哦。 主要是煎魚(yú)覺(jué)得太多的人覺(jué)得Python的語(yǔ)法較為簡(jiǎn)單,寫(xiě)出來(lái)的代碼只要符合邏輯,不需要太多的學(xué)習(xí)即可,即可從一門其他語(yǔ)言跳來(lái)用Python寫(xiě)(當(dāng)然這樣是好事,誰(shuí)都希望入門簡(jiǎn)...

    lewinlee 評(píng)論0 收藏0
  • Python什么好學(xué)生成/迭代

    摘要:為什么是斐波那契談到生成器迭代器,人們總是喜歡用斐波那契數(shù)列來(lái)舉例。那么,換句話來(lái)說(shuō),即能由推導(dǎo)式得出的數(shù)列,其實(shí)都可以用來(lái)做生成器迭代器的例子。然而,生成器和生成器類的實(shí)例都屬于迭代器。 Python有什么好學(xué)的這句話可不是反問(wèn)句,而是問(wèn)句哦。 主要是煎魚(yú)覺(jué)得太多的人覺(jué)得Python的語(yǔ)法較為簡(jiǎn)單,寫(xiě)出來(lái)的代碼只要符合邏輯,不需要太多的學(xué)習(xí)即可,即可從一門其他語(yǔ)言跳來(lái)用Python寫(xiě)...

    n7then 評(píng)論0 收藏0
  • 假裝Python高手,把類這樣改,真刺激!

    摘要:今天我們來(lái)說(shuō)一個(gè)非常實(shí)用的例子,小菜接到組長(zhǎng)老王的一個(gè)任務(wù),安排一個(gè)新的活,這個(gè)活是這樣的老王小菜啊,你幫我寫(xiě)一個(gè)登入腳本,跑十幾條命令到服務(wù)器上,然后存一下日志。這個(gè)時(shí)候,小菜偷偷的瞄了一眼組長(zhǎng)老王,常舒一口氣,總于寫(xiě)完了。 Python學(xué)了好幾年,發(fā)現(xiàn)功力還是那樣,很多同學(xué)經(jīng)常這樣抱...

    dance 評(píng)論0 收藏0
  • Python下文管理和else塊

    摘要:上下文管理器協(xié)議包含和兩個(gè)方法。因此必要時(shí)在上下文管理器函數(shù)中使用語(yǔ)句防范錯(cuò)誤。構(gòu)建臨時(shí)忽略指定異常的上下文管理器。這是個(gè)基類,用于定義基于類的上下文管理器。塊結(jié)束時(shí),按照后進(jìn)先出的順序調(diào)用棧中各個(gè)上下文管理器的方法。 導(dǎo)語(yǔ):本文章記錄了本人在學(xué)習(xí)Python基礎(chǔ)之控制流程篇的重點(diǎn)知識(shí)及個(gè)人心得,打算入門Python的朋友們可以來(lái)一起學(xué)習(xí)并交流。 本文重點(diǎn): 1、掌握if語(yǔ)句之外的el...

    Michael_Lin 評(píng)論0 收藏0
  • 后端技術(shù) - 收藏集 - 掘金

    摘要:理解迭代對(duì)象迭代器生成器后端掘金本文源自作者的一篇博文,原文是,俺寫(xiě)的這篇文章是按照自己的理解做的參考翻譯。比較的是兩個(gè)對(duì)象的內(nèi)容是后端掘金黑魔法之協(xié)程異步后端掘金本文為作者原創(chuàng),轉(zhuǎn)載請(qǐng)先與作者聯(lián)系。 完全理解關(guān)鍵字with與上下文管理器 - 掘金如果你有閱讀源碼的習(xí)慣,可能會(huì)看到一些優(yōu)秀的代碼經(jīng)常出現(xiàn)帶有 with 關(guān)鍵字的語(yǔ)句,它通常用在什么場(chǎng)景呢?今天就來(lái)說(shuō)說(shuō) with 和 上下...

    oujie 評(píng)論0 收藏0

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

0條評(píng)論

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