python with

讀寫文件時使用with可以很好地避免文件讀寫出錯或者是忘記寫關閉文件的情況
例如,打開一個文件讀寫:

f=open('F:\python\mytest\mytest\.idea\contextlib_code.py')
f.read()
f.close()

或者是:

try:
    f=open('F:\python\mytest\mytest\.idea\contextlib_code.py')
    f.read()
finally: 
    f.close()

比較麻煩,使用with語句可以省事

語法:with open('/path/to/contextlib_code.py', 'r') as f:
with語句必跟__enter__()__exit__()

意義在於:
第一步:執行__enter__()將其返回值帶給with
第二步:執行with
第三步:執行__exit__()
舉例:

引用廖雪峯python 3教程:

#-*- coding: utf-8 -*-
"""
#使用with語句,看執行先後順序
"""
class Query(object):
    def __init__(self,name):
        self.name=name
    def __enter__(self):  #第一步執行__enter__
        print('Begin')
        return self
    def __exit__(self,exc_type,exc_value,tracback):  #第三步執行:__exit__
        if exc_type:
            print('Error')
        else:
            print('End')
    def query(self):
        print('Query info about %s...' % self.name)

with Query('Bob') as q:                           #第二部執行:__with__
    q.query()

執行結果:

Begin
Query info about Bob...
End

原理是:

with context_expression [as target(s)]:
    with-body,

它的執行順序是這樣的

1.執行 context_expression,生成上下文管理器 context_manager

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

3.執行語句體 with-body

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

5.出現異常時,如果 exit(type, value, traceback) 返回 False,則會重新拋出異常,讓with 之外的語句邏輯來處理異常,這也是通用做法;如果返回 True,則忽略異常,不再對異常進行處理
還有一種方法是使用contextlibcontextmanager簡化使用__enter____exit__
使用方法:

1.用yield代替__enter__,首先執行yield前的語句,然後執行with後再次執行yield後的語句

例子:來源於廖雪峯 python3 教程

from  contextlib import contextmanager
class Query(object):
    def __init__(self,name):
        self.name=name
    def query(self):
        print('Query info about %s...' % self.name)

@contextmanager
def create_query(name):
    print('Begin')
    q=Query(name)
    yield q
    print('End')

with create_query('Bob') as q:
    q.query()

結果:

Begin
Query info about Bob...
End

當然這兩種方法都是需要有上下文的,如果一個對象沒有上下文,則沒有辦法使用withcontextmanage

@closing解決了沒有上下文的情況

可以用closing()來把該對象變爲上下文對象。例如,用with語句使用urlopen()

from contextlib import closing
from urllib.request import urlopen
with closing(urlopen('https://www.python.org'))as page:
    for line in page:
        print(line)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章