with open as f用法_[经验漫谈]Python中with上下文管理器的创建和使用

    我们在开发过程中,经常遇到需要打开文件的状况,有的开发者比较粗心,会直接使用f = open("xxx.xxx")开启文件,这样写在正常情况下没有问题,但是程序遇到了意外状况可能会导致文件损坏,所以我自己没这样写过,而是使用with open("xxx.xxx") as f的上下文管理器形式替代。本文将介绍如何自己定义一个上下文管理器。

    上下文管理器就是能够帮助你管理上下文,不管程序进行是否正常,都能够在执行前进行一些前置操作,执行完成或被迫中断后进行一步后置操作。假设现在有这样一个场景,你要模拟每天上班打卡,来到公司后和离开公司前都要打卡,不管今天是正常时间上班还是迟到了,或者上班到一半突然接到电话说媳妇要生了得赶紧去医院,都得打卡。

按照惯例,上代码先

import timeclass CheckIn:    def __init__(self, name, office_location):        self.name = name        self.office_location = office_location        self.file = None    def __enter__(self):        print(f"{self.name} 你好,你已经在{self.office_location} 完成签到打卡")        now_time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())        file = open(f"work-{now_time_str}.txt", "w")        self.file = file        return file    def __exit__(self, exc_type, exc_value, trace_back_info):        print(f"{self.name} 你好,你已经在{self.office_location} 完成签退打卡")        self.file.close()if __name__ == "__main__":    with CheckIn("华哥", "开放办公区") as pub_office:        pub_office.write("开放式办公区 签到")        now_time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())        pub_office.write(now_time_str)        pub_office.write("\n")        time.sleep(1.5)        with CheckIn("华哥", "封闭办公区") as pri_office:            pri_office.write("封闭式办公区 签到")            now_time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())            pri_office.write(now_time_str)            pri_office.write("\n")            time.sleep(1.5)            pri_office.write("封闭式办公区 签退")            now_time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())            pri_office.write(now_time_str)        pub_office.write("开放式办公区 签退")        now_time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())        pub_office.write(now_time_str) 

    这里我们定义一个类,类中有__enter__和__exit__两个特殊方法,分别实现程序前置和收尾两个操作。我在__enter__中添加了print一个字符串和开启一个文件的操作,这里直接使用open是因为可以保证这个文件开启后能正确关闭,否则像我开头说的那样,不要直接open。return的对象就是你with那行后面as的对象,在这里就是23和30行的pub_office和pri_office,当然你也可以不return东西。在__exit__函数中,我进行了print操作和关闭在__enter__中开启的文件。我们测试一下结果

54b2e07b72f2cda5305883125274567c.png

运行之后,你可以看到出现了两个文件,里面也记录了签到和签退。这里我模拟了你作为公司核心技术人员,需要穿过开放办公区来到封闭办公区域办公,所以有两次打卡。上面的结果是正常运行的状况,但是我们定义上下文管理器是为了处理非常状况,假设有天你在工作,突然老妈给你打电话说媳妇快生了,这时候你把工作扔了赶紧过去,我们在34行下面加一行

raise Exception("媳妇快生了,得赶紧去医院")

看一下是什么效果

65b73300ae0fe32b118608f0d75f3ab4.png

可以看到,四个print信息仍然运行正常,但是在work-xxx.txt中的信息则不完整,因为print信息是在__enter__和__exit__中定义的,无论如何都会运行;但是往文件中写入信息是在with块中定义的,只有运行正常时才会完整执行。

    如果将

raise Exception("媳妇快生了,得赶紧去医院")

插到27行下面,则只print两行信息,此时你是在刚在开放区打卡完就接到老妈电话,还没来得及进封闭区,所以只有开放区打卡记录。

35a5eb6bbb1f90c2e9be8aac9d3693f2.png

以上内容是Python比较高级的特性,需要多花点时间消化,如果你读到了这里,那么我将给你讲述一个更加简单的方法定义上下文管理器。以下内容是给像你这样有耐心和有求知精神的人看的。

from contextlib import contextmanager@contextmanagerdef check_in(name, office_location):    now_time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())    file = open(f"work-{now_time_str}.txt", "w")    try:        print(f"{name} 你好,你已经在{office_location} 完成签到打卡")        yield file    finally:        print(f"{name} 你好,你已经在{office_location} 完成签退打卡")        file.close()

    这是使用装饰器定义一个上下文管理器,功能和用法和上面的实现完全一致,只需将上面代码中的类名 CheckIn 改成 check_in 即可

if __name__ == "__main__":    with check_in("华哥", "开放办公区") as pub_office:        pub_office.write("开放式办公区 签到")        now_time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())        pub_office.write(now_time_str)        pub_office.write("\n")        time.sleep(1.5)        with check_in("华哥", "封闭办公区") as pri_office:            pri_office.write("封闭式办公区 签到")            now_time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())            pri_office.write(now_time_str)            pri_office.write("\n")            raise Exception("媳妇快生了,得赶紧去医院")            time.sleep(1.5)            pri_office.write("封闭式办公区 签退")            now_time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())            pri_office.write(now_time_str)        pub_office.write("开放式办公区 签退")        now_time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())        pub_office.write(now_time_str) 

    装饰器形式的实现同类形式的实现不同在于,装饰器通过yield返回as后面的内容(pub_office和pri_office),同时内部使用的是try,finally结构。装饰器的实现,尽管看起来更加简单易用,也不要用这种写法完全替代类形式的实现,在工业环境中使用上面类形式的实现更加稳妥。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值