Python魔法模块之contextlib

      今天在逛stackoverflow的时候,发现了contextlib这个模块的的作用!而且今天成功将这个模块应用到了项目中,简直爽的飞起!特此整理一篇博客,分享给大家!

一.引言

     我们在操作文件时最常用的就是使用with上下文管理器,这样会让代码的可读性更强而且错误更少,例如:

with open('/tmp/a.txt', a) as file_obj:
    file_obj.write("hello carson")

 

     按照上述这样写的好处在于,在执行完毕缩进代码块后会自动关闭文件。同样的例子还有threading.Lock,如果不使用with,需要这样写:

import threading

lock = threading.Lock()

lock.acquire()
try:
    my_list.append(item)
finally:
    lock.release()

如果使用with,那就会非常简单:

with lock:
    my_list.append(item)

创建上下文管理实际就是创建一个类,添加__enter__和__exit__方法。下面我们来实现open的上下文管理功能:

class OpenContext(object):

    def __init__(self, filename, mode):
        self.fp = open(filename, mode)

    def __enter__(self):
        return self.fp

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

        
with OpenContext('/tmp/a.txt', 'a') as file_obj:
    file_obj.write("hello 6666")

上面我们自定义上下文管理器确实很方便,但是Python标准库还提供了更加易用的上下文管理器工具模块contextlib,它是通过生成器实现的,我们不需要再创建类以及__enter__和__exit__这两个特俗的方法:

from contextlib import contextmanager

@contextmanager
def make_open_context(filename, mode):
    fp = open(filename, mode)
    try:
        yield fp
    finally:
        fp.close()

with make_open_context('/tmp/a.txt', 'a') as file_obj:
    file_obj.write("hello carson666")

在上文中,yield关键词把上下文分割成两部分:yield之前就是__init__中的代码块;yield之后其实就是__exit__中的代码块,yield生成的值会绑定到with语句as子句中的变量,例如在上面的例子中,yield生成的值是文件句柄对象fp,在下面的with语句中,会将fp和file_obj绑定到一起,也就是说file_obj此时就是一个文件句柄对象,那么它就可以操作文件了,因此就可以调用file_obj.write("hello carson666"),另外要注意的是如果yield没有生成值,那么在with语句中就不需要写as子句了,后面会结合具体的例子详解。

案例一:

# _*_ coding:utf-8 _*_
from contextlib import contextmanager

"""
contextmanager给了我们一个机会,即将原来不是上下文管理器的类变成了一个
上下文管理器,例如这里的MyResource类
"""
class MyResource:
    def query(self):
        print("query data")

@contextmanager
def make_myresource():
    print("connect to resource")
    yield MyResource()
    print("connect to resource")

with make_myresource() as r:
    r.query()

上面的例子就充分体现了contextmanager的强大作用,将一个不是上下问管理器的类 MyResource变成了一个上下文管理器,这样做的好处在于,我们就可以在执行真正的核心代码之前可以执行一部分代码,然后在执行完毕后,又可以执行一部分代码,这种场景在实际需求中还是很常见的。上面yield MyResource() 生成了一个实例对象,然后我们可以在with语句中调用类中的方法。看看最终的打印结果:

上面这样写的好处还有:假如MyResource是Flask或者其他第三方插件提供给我们的类库,如果使用自定义上下文管理器,那么就要使用手动去修改源码,在原代码的基础上添加enter和exit方法,这样做肯定不合适;现在我们可以在类MyResource的外部使用contextmanager将该类包装成为一个上下文管理器,这样既可以调用类中的方法,又可以在执行核心代码前后再执行一些相关的语句。

案例二需求

      我现在想打印 《且将生活一饮而尽》 也就是说我们要打印《 和 》;这就体现了上下文管理器的一个用法:我仅仅就是需要在我的核心代码前面和后面各执行一段代码而已:

# _*_ coding:utf-8 _*_

from contextlib import contextmanager

@contextmanager
def book_mark():
    print('《', end="")
    yield
    print('》', end="")

with book_mark():
    # 核心代码
    print('且将生活一饮而尽', end="")

打印结果:

看看实际的例子,我们通常在SQLAlchemy中使用db.session.commit(),既然有commit,那就需要做一个事务的处理。因此我们需要使用try except来处理异常,如下图所示:

一般在应用程序中,我们都有很多个db.session.commit(),那如果都要使用try来处理异常,那就太麻烦了。我们需要做的是在核心代码之前使用try,然后在核心代码执行完毕之后,加上except。因此这就使用到了上下文管理器,此时这个db是一个第三方类库SQLAlchemy,那我们如何去为它新增加一个方法呢?那我们就继承SQLAlchemy,首先导入,然后取名字:

 

上面我们就为SQLAlchemy新增了一个auto_commit方法,主要实现的是自动commit()和rollback();并将其变成了一个上下文管理器。

那么原始的代码就可以变成如下的:

如下,我们在保存user的时候也使用到了db.session.commit();所以也可以改写:

修改如下:

 不是上下文管理器的类,是不能使用with语句调用的。

转自:https://www.cnblogs.com/pyspark/articles/8819803.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值