上一篇:面向对象案例练习 | 手把手教你入门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)