# -*- encoding: utf-8 -*-
import contextlib
import subprocess
import psycopg2
'''
4、 第2章_上下文管理器
关键:
1 上下文管理器
含义: 包装任意代码块的对象
作用: 确保资源被正确清理,类似try,except;避免重复
用法: with, enter, exit
2 with语句
作用: 可以进入上下文管理器
原理: __enter__返回的结果被赋予给as关键字之后的变量
用法示例:
with open(fileName, 'r') as fr:
data = fr.read()
3 enter方法
特点: with语句的表达式的作用是返回一个遵循特定协议的对象,该对象必须定义
__enter__方法和__exit__方法
__enter__方法:
参数:只接受self参数
返回值: self
作用:执行一些配置
4 exit方法
作用: 处理包装代码块的异常
参数: self, 异常类型,异常示例,回溯
返回值: 可以为None,如果为False,就会向上传播异常;如果为True,就终止异常
样例:
class MyException(object):
def __enter__(self):
return self
def __exit__(self, excType, excInstance, traceBack):
if excInstance:
print "It has exception: {exc}".format(exc=excInstance)
return True
5 上下文装饰器
@contextlib.contextmanager
作用: 以该装饰器装饰的函数在函数执行期间返回单个值(yield)
参考:
Python高级编程
'''
class MyContext(object):
def __init__(self):
self.entered = False
def __enter__(self):
self.entered = True
return self
def __exit__(self, excType, excInstance, traceBack):
self.entered = False
def useContext():
myContext = MyContext()
print myContext.entered
with myContext:
print myContext.entered
print myContext.entered
class DBConnection(object):
def __init__(self, dbName=None, user=None,
password=None, host='localhost'):
self.dbName= dbName
self.user = user
self.password = password
self.host = host
def __enter__(self):
self.conn = psycopg2.connect(
dbname=self.dbName,
host=self.host,
user=self.user,
password=self.password
)
return self.conn.cursor()
def __exit(self, excType, excInstance, backTrace):
self.conn.close()
def useDBConn():
with DBConnection(user='luke', dbname='foo') as db:
db.execute('SELECT 1 + 1')
db.fetchall()
class MyException(object):
def __enter__(self):
return self
def __exit__(self, excType, excInstance, traceBack):
if excInstance:
print "It has exception: {exc}".format(exc=excInstance)
return True
def useMyException():
with MyException():
print 1 + 1
with MyException():
print 1 / 0
class ShellException(Exception):
def __init__(self, code, stdout='', stderr=''):
self.code = code
self.stdout = stdout
self.stderr = stderr
def __str__(self):
return 'exit code {code} - {stderr}'.format(
code=self.code,
stderr=self.stderr
)
def executeCommand(command):
proc = subprocess.Popen(command.split(' '), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
proc.wait()
stdout, stderr = proc.communicate()
if proc.returncode > 0:
raise ShellException(proc.returncode, stdout, stderr)
return stdout
@contextlib.contextmanager
def acceptError(*codes):
try:
yield
except ShellException as exc_instance:
if exc_instance.code not in codes:
raise
pass
def useContextlib():
with acceptError(1):
executeCommand('rm adadadadadadadadad')
with acceptError(1):
executeCommand('rm -m adadadadadadadadad')
def process():
useContext()
# useDBConn()
useMyException()
useContextlib()
if __name__ == "__main__":
process()