彩票网站建设平台,广东公司响应式网站建设设计,免费搭建平台网站,宣传片制作app上下文管理器
如果你有阅读源码的习惯#xff0c;可能会看到一些优秀的代码经常出现带有 “with” 关键字的语句#xff0c;它通常用在什么场景呢#xff1f;
对于系统资源如文件、数据库连接、socket 而言#xff0c;应用程序打开这些资源并执行完业务逻辑之后#xff…上下文管理器
如果你有阅读源码的习惯可能会看到一些优秀的代码经常出现带有 “with” 关键字的语句它通常用在什么场景呢
对于系统资源如文件、数据库连接、socket 而言应用程序打开这些资源并执行完业务逻辑之后必须做的一件事就是要关闭断开该资源。
比如 Python 程序打开一个文件往文件中写内容写完之后就要关闭该文件否则会出现什么情况呢极端情况下会出现 Too many open files 的错误因为系统允许你打开的最大文件数量是有限的。
同样对于数据库如果连接数过多而没有及时关闭的话就可能会出现 Can not connect to MySQL server Too many connections因为数据库连接是一种非常昂贵的资源不可能无限制的被创建。
来看看如何正确关闭一个文件。
简单使用
普通版
f open(output.txt, w)
f.write(python)
f.close()这样写有一个潜在的问题如果在调用 write 的过程中出现了异常进而导致后续代码无法继续执行close 方法无法被正常调用因此资源就会一直被该程序占用者释放。那么该如何改进代码呢
进阶版
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 代码中文件就一定会关闭。
高级版
with open(output.txt, r) as f:f.write(Python)一种更加简洁、优雅的方式就是用 with 关键字。open 方法的返回值赋值给变量 f当离开 with 代码块的时候系统会自动调用 f.close() 方法 with 的作用和使用 try/finally 语句是一样的。那么它的实现原理是什么在讲 with 的原理前要涉及到另外一个概念就是上下文管理器Context Manager。
上下文管理器
什么是上下文(context) 上下文在不同的地方表示不同的含义要感性理解。context其实说白了和文章的上下文是一个意思在通俗一点我觉得叫环境更好。.... 看这些都是上下文的典型例子理解成环境就可以(而且上下文虽然叫上下文但是程序里面一般都只有上文而已只是叫的好听叫上下文。。进程中断在操作系统中是有上有下的不过不这个高深的问题就不要深究了。。。) 任何实现了 __enter__()和 __exit__()方法的对象都可称之为上下文管理器上下文管理器对象可以使用 with 关键字。显然文件file对象也实现了上下文管理器。
那么文件对象是如何实现这两个方法的呢我们可以模拟实现一个自己的文件类让该类实现 __enter__() 和 __exit__() 方法。
class File():def __init__(self, filename, mode):self.filename filenameself.mode modedef __enter__(self):print(进入上下文管理器)self.f open(self.filename, self.mode)return self.fdef __exit__(self, *args):print(退出上下文管理器)self.f.close()def operate(self):print(在上下文管理器里面操作)__enter__() 方法返回资源对象这里就是你将要打开的那个文件对象__exit__() 方法处理一些清除工作。
这就是上下文管理协议的一个强大之处异常可以在__exit__ 进行捕获并由你自己决定如何处理是抛出呢还是在这里就解决了。在__exit__ 里返回 True没有return 就默认为 return False就相当于告诉 Python解释器这个异常我们已经捕获了不需要再往外抛了。
在 写__exit__ 函数时需要注意的事它必须要有这三个参数
exc_type异常类型exc_val异常值exc_tb异常的错误栈信息
当主逻辑代码没有报异常时这三个参数将都为 None。
因为 File 类实现了上下文管理器现在就可以使用 with 语句了。
with File(out.txt, w) as f:print(writing)f.write(hello, python)这样你就无需显示地调用 close 方法了由系统自动去调用哪怕中间遇到异常 close 方法也会被调用。
在我看来这和 Python 崇尚的优雅风格有关。
可以以一种更加优雅的方式操作创建/获取/释放资源如文件操作、数据库连接可以以一种更加优雅的方式处理异常
另一种实现
Python 还提供了一个 contextmanager 的装饰器更进一步简化了上下文管理器的实现方式。通过 yield 将函数分割成两部分yield 之前的语句在 __enter__ 方法中执行yield 之后的语句在 __exit__ 方法中执行。紧跟在 yield 后面的值是函数的返回值。
from contextlib import contextmanagercontextmanager
def my_open(path, mode):f open(path, mode)yield ff.close()调用
with my_open(out.txt, w) as f:f.write(hello , the simplest context manager)总结
总结起来使用上下文管理器有三个好处
提高代码的复用率提高代码的优雅度提高代码的可读性