了解with语句

了解with语句

在python中经常会看到with语句,最常见的with语句应该是with open(...),用过这个语句的人应该都知道这个语句意味着什么,with语句开始之后首先会初始化一些对象,在退出with语句之后会释放掉资源。

with语句就是用来管理资源的,开始with语句会创建资源,创建资源在__enter__方法之中,with语句结束之后会释放资源,释放资源在__exit__方法之中。一般情况下,判断一个对象能不能使用with语句就是判断该对象有没有实现这两个方法,比如定义一个类,该类实现了__enter____exit__方法:

class Manager:
    def __enter__(self):
        ...
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        ...

现在Manager的实例对象就可以使用with语句来管理了,为了使用方便,在标准库contextlib有很多简单易用的管理函数,介绍其中一个最常用的装饰函数contextmanager,该装饰函数用来装饰一个生成器,在yield语句之后返回资源。看一看示例:

""" with语句的本质

with exp1 [as exp2]:
    do_something
类实现了__enter__方法和__exit__方法就是一个上下文管理器
在with exp1 [as exp2]语句中执行__enter__方法
在do_something之后执行__exit__方法

使用contextlib.contextmanager函数装饰器装饰一个生成器来创建上下文管理器
@contextlib.contextmanager
def generate(...):
    <setup>
    try:
        yield <value>
    finally:
        <cleanup>

the statistics of this file:
lines(count)    understand_level(h/m/l)    classes(count)    functions(count)    fields(count)
000000000085    ----------------------m    00000000000001    0000000000000002    ~~~~~~~~~~~~~
"""

import time
import sqlite3
from contextlib import contextmanager

__author__ = '与C同行'


class ContextDb:
    def __init__(self, db):
        self.db = db

    def __enter__(self):
        self.cursor = self.db.cursor()
        return self.cursor

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


@contextmanager
def db_context_manager(db):
    cursor = db.cursor()
    try:
        yield cursor
    finally:
        cursor.close()
        db.close()


def print_pretty_outcome(cursor):
    print('-' * 80)
    all_outcome = cursor.fetchall()
    for column_desc in cursor.description:
        print(f'{column_desc[0]:<20}', end='')
    print()
    for item in all_outcome:
        for cell in item:
            try:
                print(f'{cell:<20}', end='')
            except TypeError:
                cell = 'None'
                print(f'{cell:<20}', end='')
        print()
    print('-' * 80)
    print()


if __name__ == '__main__':
    print(f'当前时间:{time.ctime()}')
    print()

    conn = sqlite3.connect('test.db')
    print('使用类创建with上下文管理器')
    with ContextDb(conn) as c:
        c.execute('select 3*3')
        print_pretty_outcome(c)

    conn = sqlite3.connect('test.db')
    print('使用contextmanager装饰器创建上下文管理器')
    with db_context_manager(conn) as c:
        c.execute('select 2+2')
        print_pretty_outcome(c)

结果如下:
在这里插入图片描述
上面的示例创建了一个ContextDb类,该类实现了__enter____exit__方法,在__enter__方法之中返回游标,在__exit__方法之中关闭游标和数据库。另外创建了一个db_context_manager生成器,该生成器用contextmanager装饰,在yield语句之后返回游标,在finally语句之后关闭游标和数据库。

喜欢python的朋友可以关注微信公众号“与C同行”:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值