python中上下文管理器

2018-09-04  本文已影响8人  转身丶即天涯

什么是上下文管理器?

代码的环境就是上下文,实现了上下文管理器协议的类产生的实例就是上下文管理器对象。
在类中声名enterexit方法的就时实现了上下文管理器协议,也就是说,只要定义了这两个方法,这个类的实例就是上下文管理器对象。

在数据库中的应用

在不适用上下文管理器对象时,我们一般按照连接数据库,sql操作,读取数据,断开连接这样的顺序进行编码,可是连接数据库和断开连接这两部是所有操作都必须要做的事,所以当有大量sql时,按照这样的逻辑些代码会造成大量的冗余代码。
我们先来看一下最原始的写法:

class Database():
    def __init__(self):
        self.connected = False

    def connect(self):
        self.connected = True

    def close(self):
        self.connected = False

    def query(self):
        if self.connected:
            return "query data"
        else:
            raise ValueError("DB not connected.")

def handle_query():
    db = Database()
    db.connect()
    print("handling......", db.query())
    db.close()

上面这段代码中,创建了一个数据库类Database,里面定义了一个connected属性,用来表示是否已经连接上数据库。
connect方法代表连接数据库操作。close方法代表关闭数据库连接。query方法代表查询操作。
这是最容易想到,也是最基础的操作逻辑。

生成器也能解决这个问题

生成器本质上是一个方法,就像在你所写的函数上套了一层接口。看一个简单示例

def dbconn(fn):
    def wrapper(*args, **kwargs):
        db = Database()
        db.connect()
        ret = fn(db, *args, **kwargs)
        db.close()
        return ret
    return wrapper

@dbconn
def handle_query(db=None):
    print("handle---", db.query())

with可以更优雅的解决这个问题

class Database():
    def __init__(self):
        self.connected = False

    def connect(self):
        self.connected = True

    def close(self):
        self.connected = False

    def query(self):
        if self.connected:
            return "query data"
        else:
            raise ValueError("DB not connected.")

    def __enter__(self):
        self.connect()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()

# 使用with来解决
def handle_query():
    with Database() as db:
        print("handle...", db.query())

# 调用handle_query()
handle_query()

可以明显的看到,Database这个类中加入了enterexit方法。
这样Database()就产生了一个实现了上下文管理器协议的对象,就可以使用with语句了。
with语句会自动处理连接和断开。

with语句怎么就自动处理了呢?

当然还是需要我们使用代码来控制的。首先with Database() as db: 这句代码中的db,就是enter方法的返回值。
而且执行这句话的时候代码会先执行enter方法,这时就做了连接数据库的操作。
然后才是执行了print("handle...", db.query())这句代码,表示处理查询sql。
当print语句(也就是查询语句)执行完了,会回调exit方法,在这里写上关闭数据库连接的代码。
这样我们就不用无限制的写连接和断开的代码了。完美解决。

这个exit方法很安全,因为当with语句中的函数体引发了异常时,也会调用eixt方法,这样就会断开数据库的连接了。

上一篇 下一篇

猜你喜欢

热点阅读