With关键字的使用

    技术2022-08-11  87

    With关键字的使用

    对于系统资源如⽂件、数据库连接、socket ⽽⾔,应⽤程序打开这些资源并执⾏完业务逻辑之后,必须做的⼀件事就是要关闭(断开)该资源。

    ⽐如 Python 程序打开⼀个⽂件,往⽂件中写内容,写完之后,就要关闭该⽂件,否则会出现什么情况呢?极端情况下会出现 “Too many open files” 的错误,因为系统允许你打开的最⼤⽂件数量是有限的。

    同样,对于数据库,如果连接数过多⽽没有及时关闭的话,就可能会出现 “Can not connect to MySQL server Too many connections”,因为数据库连接是⼀种⾮常昂贵的资源,不可能⽆限制的被创建。

    来看看如何正确关闭⼀个⽂件。 普通版:

    def m1(): f = open(“output.txt”, “w”) f.write(“python之禅”) f.close() 这样写有⼀个潜在的问题,如果在调⽤ write 的过程中,出现了异常进⽽导致后续代码⽆法继续执⾏,close⽅法⽆法被正常调⽤,因此资源就会⼀直被该程序占⽤者释放。那么该如何改进代码呢? 污水流量计 进阶版:

    def m2(): f = open(“output.txt”, “w”) try: f.write(“python之禅”) except IOError: print(“oops error”) finally: f.close() 改良版本的程序是对可能发⽣异常的代码处进⾏ try 捕获,使⽤ try/finally 语句,该语句表示如果在 try 代码块中程序出现了异常,后续代码就不再执⾏,⽽直接跳转到 except 代码块。⽽⽆论如何,finally 块的代码最终都会被执⾏。因此,只要把 close 放在 finally 代码中,⽂件就⼀定会关闭。

    ⾼级版:

    def m3(): with open(“output.txt”, “r”) as f: f.write(“Python之禅”) # 不需要再手动去关闭文件 try: with open(‘01-练习.py’, ‘r’)as file: file.read() # 不需要再手动的关闭文件 except FileNotFoundError: print(‘文件未找到’) ⼀种更加简洁、优雅的⽅式就是⽤ with 关键字。open ⽅法的返回值赋值给变量 f,当离开 with 代码块的时候,系统会⾃动调⽤ f.close() ⽅法, with 的作⽤和使⽤ try/finally 语句是⼀样的。

    上下文管理器 with语句实质上是⼀个上下⽂管理器,很多需要手动关闭的连接,比如说,文件连接,socket连接,数据库的连接都能使用with关键字来自动关闭连接。 with语句后的对象都会有 enter() 和 exit() ⽅法。 在进⼊到上下⽂时,会⾃动调⽤ enter() ⽅法,程序正常执⾏完成,或者出现异常中断的时候,都会调⽤ exit() ⽅法。

    class MyContext(object): def init(self, name, age): self.name = name self.age = age

    def __enter__(self): print('调⽤了enter⽅法') return self def test(self): 1 / 0 print(self.name + '调⽤了test⽅法') def __exit__(self, exc_type, exc_val, exc_tb): print('调⽤了exit⽅法') print(exc_type, exc_val, exc_tb)

    with MyContext(‘zhangsan’, 18) as context: context.test() class Demo(object): def init(self): print(’__enter__方法被执行了’) return self

    def __exit__(self, exc_type, exc_val, exc_tb): print('__exit__方法被调用了')

    def create_obj(): x = Demo() return x

    #y = create_obj() #d = y.enter()

    with create_obj() as d: # as 变量名 # 变量 d 不是 create_obj的返回结果 # 它是创建的对象 y 调用 enter 之后的返回结果 print(d)

    Processed: 0.013, SQL: 9