1. 程式人生 > >python中with...as的用法

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 一起工作的物件列表

  1. fie
  2. decimal.Context
  3. thread.LockType
  4. thread.RLock
  5. thread.Condition
  6. thread.Semaphore

作者:遠方_Eden
來源:CSDN
原文:https://blog.csdn.net/qiqicos/article/details/79200089