With关键字的使用 | 手把手教你入门Python之七十八

上一篇:面向对象案例练习 | 手把手教你入门Python之七十七
下一篇:自定义异常 | 手把手教你入门Python之七十九

本文来自于千锋教育在阿里云开发者社区学习中心上线课程《Python入门2020最新大课》,主讲人姜伟。

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)

配套视频

上一篇:ExecutorService对象的shutdown()和shutdownNow()的区别


下一篇:好程序员HTML5技术分享前端自动化工具推荐