久久国产乱子伦精品免费M,亚洲一区二区三区91,欧美国产在线视频,国产精品视频久久

Python with提前退出:坑與解決方案

問題的起源

早些時候使用with實現了一版全局進程鎖,希望實現以下效果:

Python with提前退出:坑與解決方案

全局進程鎖本身不用多說,大部分都依靠外部的緩存來實現的,redis上用的是setnx,有時候根據需要加上緩存擊穿問題、隨機延后以防止對緩存本身造成壓力。

當時同樣寫了單元測試來測試這段代碼的有效性:

Python with提前退出:坑與解決方案

看起來非常完美地通過了。

這樣的一個全局進程鎖是通過__enter__方法拋出異常, __exit__方法中捕獲異常來實現的:

Python with提前退出:坑與解決方案

看起來還不錯,畢竟單元測試都過了。

但是,這樣的實現是有問題的:

原因在于__exit__ 的執行不是包在__enter__ 之外的,因此__enter__拋出的異常,不會被__exit__捕獲。

上面的單元測試恰好通過,是因為其中有兩個with語句,外面的with 捕獲的其實是里面的__enter__ 拋出的異常

使用改進后的單元測試:

Python with提前退出:坑與解決方案

就會發現單元測試過不去了。

這個問題是我試圖使用with實現另一個邏輯:AB測試 時出現的,同樣是__enter__拋出異常,__exit__ 試圖捕獲:

Python with提前退出:坑與解決方案

調試沒有通過的單元測試的時候發現,拋出異常后根本沒有執行到__enter__。

第一種解決方案

既然想明白了with的執行順序,那么第一種解決方案就呼之欲出了:既然__exit__捕獲的異常在__enter__執行完成之后,那么我們提供一個函數確認一下就可以了,把ABContext實現改成這樣:

Python with提前退出:坑與解決方案

使用的時候:

Python with提前退出:坑與解決方案

但這樣的解決方法并不優雅,萬一使用這個ABContext的時候忘記用ensure方法了,那么就等于完全沒用這個Context方法,太容易失誤了,而且代碼也失去了Pythonic的性質。

第二種解決方法

翻了一下contextlib的標準庫文檔,發現有一個已經廢棄的函數:contextlib.nested

Python with提前退出:坑與解決方案

可以執行多個上下文:

Python with提前退出:坑與解決方案

這個廢棄的特性在Python2.7之后,可以直接由with關鍵字執行,形如:

Python with提前退出:坑與解決方案

這個特性還不錯,根據__enter__的執行順序的話,那么我們可以實現一個由第一個 context的__exit__來捕獲,第二個context的__enter__來拋出異常,

如同這樣:

Python with提前退出:坑與解決方案

結合前面我們實現的ABContext的使用是這樣的:

Python with提前退出:坑與解決方案

good,單元測試就這樣過了!

能不能再給力點?

確實,在with里要寫倆context有點蛋疼,并不是特別優雅,能不能還是回到最初的那種用法:我們只用寫一條context,這一個context做到了兩個context的事情?

要是nested那個函數還在就好了。。要的其實就是它的功能。

Python3.1之后contextlib提供了一個ExitStack的功能來提供一個模擬的功能,但試了一下發現,實際上只調用了__enter__方法,但沒有做對應的異常捕獲。

第三種解決方案

哈哈哈哈把自己繞到圈子里去了,想了一下,同樣是一個縮進的代碼塊,為什么不能用if來解決呢!不就是個:

Python with提前退出:坑與解決方案

的問題。。。

TIL

總之學到了contextlib里的一些有用的函數和裝飾器,也第一次發現with可以放個context。

雖然放多個context的動態構造還有待研究,with 后面的代碼塊也不能填一個元組或者列表。。惆悵。。

好啦!今天的分享到這里就結束了,希望大家持續關注馬哥教育官網,每天都會有大量優質內容與大家分享!聲明:文章轉載于網絡,版權歸原作者所有,如有侵權,請及時聯系刪除!

相關新聞

歷經多年發展,已成為國內好評如潮的Linux云計算運維、SRE、Devops、網絡安全、云原生、Go、Python開發專業人才培訓機構!

    1. 主站蜘蛛池模板: 出国| 霸州市| 淮滨县| 肃宁县| 会同县| 体育| 曲阳县| 灵寿县| 右玉县| 综艺| 商洛市| 通渭县| 昭觉县| 九江市| 阿尔山市| 共和县| 前郭尔| 青阳县| 开封市| 名山县| 伊宁县| 体育| 江口县| 江陵县| 东莞市| 通海县| 德保县| 郓城县| 无锡市| 抚宁县| 潮州市| 抚松县| 曲水县| 当阳市| 台南县| 万载县| 永泰县| 双鸭山市| 格尔木市| 土默特右旗| 文登市|