Python中的with是測試常用到的資源打開利器

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"在我們完成自動化測試代碼的時候,總會遇見各種讀取文本文件、讀取Excel等類型的操作。這種代碼我們時刻都要記得打開文件後要關閉文件。往往關閉文件卻是我們常常忘記的。針對上述這樣的情況,python提供了with就可以完美解決這個問題,這也是python的語法糖。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"Syntactic sugar,也就是語法糖,它指計算機語言中添加的某種語法,這種語法對語言的功能沒有影響,但是更方便程序員使用。語法糖讓程序更加簡潔,有更高的可讀性。語法糖就是爲了避免coder出現錯誤並提高效率的語法層面的一種優雅的解決方案。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"一個常規的文件打開代碼"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"下面是一個常規的打開文件的代碼,那麼你可以從下面代碼中看出什麼問題嗎?"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":" rf= open('crisschan.txt','r')\n\n print(rf.readlines())\n\n rf.close()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"上面代碼在讀取文件過程中如果發生異常,那麼close()函數就沒有辦法被執行到了,這也就導致了文件沒有辦法關閉了。因此,很多教程上都告訴大家要用try except將文件讀取的異常捕獲到,那麼我們改造一下如下:"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":" try:\n\n \t\trf = open('email.txt','r')\n\n \t\tprint(rf.readlines())\n\n except:\n\n \t\tprint('Oooooops!What\\'s up!')\n\n finally:\n\n \t\trf.close()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"好了,上面的代碼無論如何我們都會執行close函數了,這樣是不是已經很好了。但是上面的代碼太繁瑣了,這樣的coding段,python提供了with,讓上述的代碼更簡單:"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"with open('email.txt','r') as rf:\n\n print(rf.readlines())"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"上面是不是很簡潔,是不是也很優雅呢。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":" with是怎麼幹活的"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"with context_expression [as target(s)]:\n\n \t\tdo_somthing()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"上述代碼片段中,`context_expression`會返回一個上下文管理器對象,這個對象並不賦值給`as`後的`target(s)`,而是上下文管理器的`__enter__()`函數的返回值賦值給 `target(s)`。當with全部的代碼段都執行完成後,會調用`__exit__()`。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"具體例子如下:"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"class SampleWith(object):\n\n def __init__(self):\n\n \t\tprint('init this class')\n\n def __enter__(self):\n\n \t\tprint('this is __enter__')\n\n \t\treturn 'CrissChan'\n\n def __exit__(self, exc_type, exc_val, exc_tb):\n\n \t\tprint('this is __exit__')\n\n def call(self):\n\n \t\tprint('call funtion')\n\n if __name__ == '__main__':\n\n \t\twith SampleWith() as sw:\n\n \t\t\t\tprint('sw is :',sw)\n\n \t\t\t\tsw.call()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"運行完後,輸入如下:"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"init this class\n\n this is __enter__\n\n sw is : CrissChan\n\n this is __exit__\n\n Traceback (most recent call last):\n\n File \"/Users/crisschan/PycharmProjects/try_space/flv2mp4.py\", line 24, in \n\n sw.call()\n\n AttributeError: 'str' object has no attribute 'call'"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"那下面我來給你解釋一下上面的代碼段以及結果輸出。"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"1、在main函數中我們使用with調用了SampleWith(),這是時候我們就會看到了我們險實力話了一個SampleWith類,調用了他的`__init__(self)`構造函數,"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"2、接下來因爲我們使用了with這個語法糖,因此下面調用了`__enter__(self)`"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"3、在後面我使用了`as sw`,也就是我將`__enter__(self)`的return賦值給了`sw`,那麼也就是說`sw`存儲的是字符串`CrissChan`,那麼也就打印了`sw is : CrissChan`"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"4、後面調用了sw.call()就出了問題,因爲字符串沒有call方法。但是仍舊進入了`__exit__(self, exc_type, exc_val, exc_tb)`函數。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"下面我將上面有報錯的代碼修改一下,如下:"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"class SampleWith(object):\n\n def __init__(self):\n\n \t\tprint('init this class')\n\n def __enter__(self):\n\n \t\tprint('this is __enter__')\n\n \t\treturn 'CrissChan'\n\n def __exit__(self, exc_type, exc_val, exc_tb):\n\n \t\tprint('this is __exit__')\n\n def call(self):\n\n \t\tprint('call funtion')\n\n if __name__ == '__main__':\n\n \t\twith SampleWith() as sw:\n\n \t\t\tprint('sw is :',sw)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"上面代碼就不會報錯了。從上面可以看出就算中間除了異常,放在`__exit__()`中的邏輯段還是會被執行的。想要了解更多請看官方的文檔[pep-403]("},{"type":"text","marks":[{"type":"underline"},{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"https://www.python.org/dev/peps/pep-0343/"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":")"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"特別備註:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":" exit()方法中有3個參數, exc_type, exc_val, exc_tb,這些參數在異常處理中相當有用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":" exc_type: 錯誤的類型"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":" exc_val: 錯誤類型對應的值"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":" exc_tb: 代碼中錯誤發生的位置"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章