python中with...as的用法
with…as,就是個python控制流語句,像 if ,while一樣。
with…as語句是簡化版的try except finally語句。
那我們先理解一下try…except…finally語句是幹啥的。實際上,try…except語句和try…finally語句是兩種語句,用於不同的場景。但是當二者結合在一起時,可以“實現穩定性和靈活性更好的設計”。
try…except語句
用於處理程式執行過程中的異常情況,比如語法錯誤、從未定義變數上取值等等,也就是一些python程式本身引發的異常、報錯。比如你在python下面輸入 1 / 0:
>>> 1/0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
系統會給你一個ZeroDivisionError的報錯。
說白了就是為了防止一些報錯影響你的程式繼續執行,就用try語句把它們抓出來(捕獲)。
try…except的標準格式:
try:
## normal block
except A:
## exc A block
except:
## exc other block
else:
## noError block
程式執行流程是:
–>執行normal block
–>發現有A錯誤,執行 exc A block(即處理異常)
–>結束
如果沒有A錯誤呢?
–>執行normal block
–>發現B錯誤,開始尋找匹配B的異常處理方法,發現A,跳過,發現except others(即except:),執行exc other block
–>結束
如果沒有錯誤呢?
–>執行normal block
–>全程沒有錯誤,跳入else 執行noError block
–> 結束
Tips: 我們發現,一旦跳入了某條except語句,就會執行相應的異常處理方法(block),執行完畢就會結束。不會再返回try的normal block繼續執行了。
except後面還能跟表示式的! 所謂的表示式,就是錯誤的定義。也就是說,我們可以捕捉一些我們想要捕捉的異常。而不是什麼異常都報出來。
try…finallly語句
用於無論執行過程中有沒有異常,都要執行清場工作。好的 現在我們看看他倆合在一起怎麼用!!
try:
execution block ##正常執行模組
except A:
exc A block ##發生A錯誤時執行
except B:
exc B block ##發生B錯誤時執行
except:
other block ##發生除了A,B錯誤以外的其他錯誤時執行
else:
if no exception, jump to here ##沒有錯誤時執行
finally:
final block ##總是執行
tips: 注意順序不能亂,否則會有語法錯誤。如果用else就必須有except,否則會有語法錯誤。
try:
a = 1 / 2
print(a)
print(m) # 丟擲NameError異常
b = 1 / 0
print(b)
c = 2 / 1
print(c)
except NameError:
print("Ops!!") # 捕獲到異常
except ZeroDivisionError:
print("Wrong math!!")
except:
print("Error")
else:
print("No error! yeah!")
finally: # 是否異常都執行該程式碼塊
print("Successfully!")
輸出:
0.5
Ops!!
Successfully!
1
2
3
try語句終於搞清楚了! 那麼可以繼續with…as的探險了
with…as語句
with as 語句的結構如下:
with expression [as variable]:
with-block
看這個結構我們可以獲取至少兩點資訊 1. as可以省略 2. 有一個句塊要執行
所謂上下文管理協議,其實是指with後面跟的expression。這個expression一般都是一個類的實體。這個類的實體裡面要包含有對__enter__和__exit__函式的定義才行。
除了給類定義一些屬性之外,還可以定義類的方法。也就是允許對類的內容有哪些操作,最直觀的方法就是用dir()函式來看一個類的屬性和方法。比如要檢視字串類有哪些屬性和方法:
>>> dir(str)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
類,除了python內建的,當然還可以自己定義! 所以除了expression表示一些含有這兩種方法的內建類,還可以自己定義類,讓他們含有enter和exit方法。
with…as語句執行順序:
–>首先執行expression裡面的__enter__函式,它的返回值會賦給as後面的variable,
想讓它返回什麼就返回什麼,只要你知道怎麼處理就可以了,如果不寫as variable,返回值會被忽略。
–>然後,開始執行with-block中的語句,不論成功失敗(比如發生異常、錯誤,
設定sys.exit()),在with-block執行完成後,會執行expression中的__exit__函式。
當with…as語句中with-block被執行或者終止後,這個類物件應該做什麼。如果這個碼塊執行成功,則exception_type,exception_val, trace的輸入值都是null。如果碼塊出錯了,就會變成像try/except/finally語句一樣,exception_type, exception_val, trace 這三個值系統會分配值。
這個和try finally函式有什麼關係呢?其實,這樣的過程等價於:
try:
執行 __enter__的內容
執行 with_block.
finally:
執行 __exit__內容
那麼__enter__和__exit__是怎麼用的方法呢?我們直接來看一個栗子好了。
程式無錯的例子:
class Sample(object): # object類是所有類最終都會繼承的類
def __enter__(self): # 類中函式第一個引數始終是self,表示建立的例項本身
print("In __enter__()")
return "Foo"
def __exit__(self, type, value, trace):
print("In __exit__()")
def get_sample():
return Sample()
with get_sample() as sample:
print("sample:", sample)
print(Sample) # 這個表示類本身 <class '__main__.Sample'>
print(Sample()) # 這表示建立了一個匿名例項物件 <__main__.Sample object at 0x00000259369CF550>
輸出結果:
In __enter__()
sample: Foo
In __exit__()
<class '__main__.Sample'>
<__main__.Sample object at 0x00000226EC5AF550>
步驟分析:
–> 呼叫get_sample()函式,返回Sample類的例項;
–> 執行Sample類中的__enter__()方法,列印"In__enter_()“字串,並將字串“Foo”賦值給as後面的sample變數;
–> 執行with-block碼塊,即列印"sample: %s"字串,結果為"sample: Foo”
–> 執行with-block碼塊結束,返回Sample類,執行類方法__exit__()。因為在執行with-block碼塊時並沒有錯誤返回,所以type,value,trace這三個arguments都沒有值。直接列印"In__exit__()"
程式有錯的例子:
class Sample:
def __enter__(self):
return self
def __exit__(self, type, value, trace):
print("type:", type)
print("value:", value)
print("trace:", trace)
def do_something(self):
bar = 1 / 0
return bar + 10
with Sample() as sample:
sample.do_something()
輸出結果:
type: <class 'ZeroDivisionError'>
value: division by zero
trace: <traceback object at 0x0000019B73153848>
Traceback (most recent call last):
File "F:/機器學習/生物資訊學/Code/first/hir.py", line 16, in <module>
sample.do_something()
File "F:/機器學習/生物資訊學/Code/first/hir.py", line 11, in do_something
bar = 1 / 0
ZeroDivisionError: division by zero
步驟分析:
–> 例項化Sample類,執行類方法__enter__(),返回值self也就是例項自己賦值給sample。即sample是Sample的一個例項(物件);
–>執行with-block碼塊: 例項sample呼叫方法do_something();
–>執行do_something()第一行 bar = 1 / 0,發現ZeroDivisionError,直接結束with-block程式碼塊執行
–>執行類方法__exit__(),帶入ZeroDivisionError的錯誤資訊值,也就是type,value, trace,並列印它們。
可以和with 一起工作的物件列表
- fie
- decimal.Context
- thread.LockType
- thread.RLock
- thread.Condition
- thread.Semaphore
作者:遠方_Eden
來源:CSDN
原文:https://blog.csdn.net/qiqicos/article/details/79200089