# -*- encoding: utf-8 -*-
from contextlib import contextmanager
import logging
'''
第43條: 考慮以contextlib和with語句來改寫可複用的try/finally代碼
關鍵:
1 with語句
作用: 進行文件關閉,資源清理,鎖的獲取與釋放等
支持with:
方式1:用contextlib模塊處理自己編寫的對象和函數
提供了contextmanager的裝飾器
方式2: 定義一個類,提供__enter__和__exit__的特殊方法
2 使用帶有目標的with語句
用法: 傳給with語句的那個情境管理器,本身可以返回一個對象
with中的as: 指定一個局部變量,會把情境管理器的對象,賦給這個局部變量
應用場景:
打開文件,as指定變量接收open返回的文件句柄
3 情境管理器
用法:在情境管理器中通過yield語句返回值,然後另自己的函數把該值提供給
as指定的目標變量
用法示例:
@contextmanager
def logLevel(level, name):
logger = logging.getLogger(name)
oldLevel = logger.getEffectiveLevel()
logger.setLevel(level)
try:
yield logger
finally:
logger.setLevel(oldLevel)
with logLevel(logging.DEBUG, 'myLog') as logger:
logger.debug('I like python.')
4 總結
contextlib.contextmanager裝飾器可以修飾函數,來讓函數支持with語句,
只需要在該函數中原來return返回的地方修改爲yield, 則as關鍵字就可以將
返回的結果賦值給一個局部變量。
參考:
Effectiv Python 編寫高質量Python代碼的59個有效方法
'''
def func():
logging.debug('debug data')
logging.error('error data')
logging.debug('debug data')
@contextmanager
def debugLogging(level):
logger = logging.getLogger()
oldLevel = logger.getEffectiveLevel()
logger.setLevel(level)
try:
yield
finally:
logger.setLevel(oldLevel)
def useContextManager():
with debugLogging(logging.DEBUG):
print "Inside"
func()
print "After"
func()
with logLevel(logging.DEBUG, 'myLog') as logger:
logger.debug('I like python.')
logging.debug('This will not print.')
logger = logging.getLogger('myLog')
logger.debug('Debug will do not print.')
logger.error('Error will print.')
def useWith():
with open('/tmp/data.txt', 'w') as handle:
handle.write("I like python.")
@contextmanager
def logLevel(level, name):
logger = logging.getLogger(name)
oldLevel = logger.getEffectiveLevel()
logger.setLevel(level)
try:
yield logger
finally:
logger.setLevel(oldLevel)
def process():
useContextManager()
useWith()
if __name__ == "__main__":
process()