Python高级编程 读书笔记: 4、 第2章_上下文管理器

# -*- 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() 

 

你可能感兴趣的:(Professional,Python)