Python進階With文法

來源:互聯網
上載者:User

標籤:函數式編程   python進階with   

一:起因

(0)Python的基本文法,對於一個學過其他語言的人來說,比較容易;但是要是熟練的應用 和 掌握Python的進階文法還是有一段路要走的。

(1)With語句代替try……finally語句;yield文法之產生器generator,序列產生器;函數式編程(Map/Reduce/Filter等 ps:這裡的Map/Reduce不是Hadoop的MR)

(3)樣本請詳見

二:With基本文法

(0)要說With文法,首先講一講 上下文管理器

舉個例子,你在寫Python代碼的時候經常將一系列操作放在一個語句塊中:

當某條件為真 – 執行這個語句塊;當某條件為真 – 迴圈執行這個語句塊;有時候我們需要在當程式在語句塊中運行時保持某種狀態,並且在離開語句塊後結束這種狀態。

所以,事實上上下文管理器的任務是 – 代碼塊執行前準備,代碼塊執行後收拾。

看代碼是最好的學習方式,來看看我們通常是如何開啟一個檔案並寫入”Hello World”?

filename = 'my_file.txt'mode = 'w' # Mode that allows to write to the filewriter = open(filename, mode)writer.write('Hello ')writer.write('World')writer.close()

1-2行,我們指明檔案名稱以及開啟檔案(寫入)。

第3行,開啟檔案,4-5行寫入“Hello world”,第6行關閉檔案。

這樣不就行了,為什麼還需要上下文管理器?但是我們忽略了一個很小但是很重要的細節:如果我們沒有機會到達第6行關閉檔案,那會怎樣?

舉個例子,磁碟已滿,因此我們在第4行嘗試寫入檔案時就會拋出異常,而第6行則根本沒有機會執行。

當然,我們可以使用try-finally語句塊來進行封裝:
writer = open(filename, mode)try:    writer.write('Hello ')    writer.write('World')finally:    writer.close()

finally語句塊中的代碼無論try語句塊中發生了什麼都會執行。因此可以保證檔案一定會關閉。這麼做有什麼問題嗎?當然沒有,但當我們進行一些比寫入“Hello world”更複雜的

事情時,try-finally語句就會變得醜陋無比。例如我們要開啟兩個檔案,一個讀一個寫,兩個檔案之間進行拷貝操作,那麼通過with語句能夠保證兩者能夠同時被關閉。

(1)with 語句的文法格式如下:

 with context_expression [as target(s)]:        with-body
這裡 context_expression 要返回一個上下文管理器對象,該對象並不賦值給 as 子句中的 target(s) ,如果指定了 as 子句的話,會將上下文管理器的 __enter__() 方法的返

回值賦值給 target(s)。target(s) 可以是單個變數,或者由“()”括起來的元組(不能是僅僅由“,”分隔的變數列表,必須加“()”)。

(2)Python 對一些內建對象進行改進,加入了對上下文管理器的支援,可以用於 with 語句中,比如可以自動關閉檔案、線程鎖的自動擷取和釋放等。假設要對一個檔案進行

操作,使用 with 語句可以有如下代碼:使用 with 語句操作檔案對象 

with open(r'somefileName') as somefile:        for line in somefile:            print line            # ...more code
這裡使用了 with 語句,不管在處理檔案過程中是否發生異常,都能保證 with 語句執行完畢後已經關閉了開啟的檔案控制代碼。

(3)如果使用傳統的 try/finally 範式,則要使用類似如下代碼:(用於和with的對比)

somefile = open(r'somefileName')    try:        for line in somefile:            print line            # ...more code    finally:        somefile.close()

比較起來,使用 with 語句可以減少編碼量。已經加入對上下文管理協議支援的還有模組 threading、decimal 等。

三:執行個體說明

(1)with 語句的執行過程類似如下代碼塊:

    context_manager = context_expression    exit = type(context_manager).__exit__      value = type(context_manager).__enter__(context_manager)    exc = True   # True 表示正常執行,即便有異常也忽略;False 表示重新拋出異常,需要對異常進行處理    try:        try:            target = value  # 如果使用了 as 子句            with-body     # 執行 with-body        except:            # 執行過程中有異常發生            exc = False            # 如果 __exit__ 返回 True,則異常被忽略;如果返回 False,則重新拋出異常            # 由外層代碼對異常進行處理            if not exit(context_manager, *sys.exc_info()):                raise    finally:        # 正常退出,或者通過 statement-body 中的 break/continue/return 語句退出        # 或者忽略異常退出        if exc:            exit(context_manager, None, None, None)         # 預設返回 None,None 在布爾上下文中看做是 False
執行 context_expression,產生上下文管理器 context_manager

調用上下文管理器的 __enter__() 方法;如果使用了 as 子句,則將 __enter__() 方法的返回值賦值給 as 子句中的 target(s)

執行語句體 with-body

不管是否執行過程中是否發生了異常,執行內容管理器的 __exit__() 方法,__exit__() 方法負責執行“清理”工作,如釋放資源等。如果執行過程中沒有出現異常,或者語句體中執行了語句 break/continue/return,則以 None 作為參數調用 __exit__(None, None, None) ;如果執行過程中出現異常,則使用 sys.exc_info 得到的異常資訊為參數調用 __exit__(exc_type, exc_value, exc_traceback)

出現異常時,如果 __exit__(type, value, traceback) 返回 False,則會重新拋出異常,讓with 之外的語句邏輯來處理異常,這也是通用做法;如果返回 True,則忽略異常,不再對異常進行處理

(2)另外python庫中還有一個模組contextlib,使你不用構造含有__enter__, __exit__的類就可以使用with:(更加實用了)

>>> from contextlib import contextmanager>>> from __future__ import with_statement>>> @contextmanager... def context():...     print 'entering the zone'...     try:...         yield...     except Exception, e:...         print 'with an error %s'%e...         raise e...     else:...         print 'with no error'...>>> with context():...     print '----in context call------'...entering the zone----in context call------with no error

(3)@property 可以將python定義的函數“當做”屬性訪問,從而提供更加友好訪問方式,但是有時候setter/getter也是需要的

class Parrot:    def __init__(self):        self._voltage = 100000    @property    def voltage(self):        """Get the current voltage."""        return self._voltageif __name__ == "__main__":    # instance    p = Parrot()    # similarly invoke "getter" via @property    print p.voltage    # update, similarly invoke "setter"    p.voltage = 12


Python進階With文法

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.