1 什么是上下文管理器?
上下文管理器(Context Manager) 是一种实现了特定协议的对象,能够在进入上下文和退出上下文时执行一些操作。
在 Python 中,只要一个对象实现了下面两个方法:
__enter__(self)
:进入上下文时调用。
__exit__(self, exc_type, exc_val, exc_tb)
:退出上下文时调用(无论是否发生异常都会执行)。
它就可以作为上下文管理器被 with
语句使用。
2 为什么要使用上下文管理器
在编程中,我们经常需要对资源进行成对操作,例如:
- 打开文件后,必须关闭。
- 获取锁后,必须释放。
- 数据库连接,需要在使用完后关闭。
- 网络连接,需要断开。
如果忘记释放资源,肯呢个会引发内存泄漏、死锁、文件句柄耗尽等问题。
上下文管理器可以自动帮我们完成清理工作,即使代码中途抛出异常也不影响。
3 with
语句的工作原理
with 语句的基本用法:
with 表达式 [as 变量]:
代码块
底层执行过程等价于:
manager = 表达式
exit_method = manager.__exit__
value = manager.__enter__()
try:
代码块
except Exception as e:
exit_method(type(e), e, e.__traceback__)
raise
else:
exit_method(None, None, None)
也就是说:
__enter__()
用于初始化资源,并返回可用对象。
__exit__()
用于清理资源,不论是否出现异常都会执行。
4 常见场景
4.1 文件操作
with open("data.txt", "r", encoding="utf-8") as f:
content = f.read()
好处:
4.2 数据库连接
import sqlite3
with sqlite3.connect("test.db") as conn:
cursor = conn.cursor()
cursor.execute("CREATE TABLE IF NOT EXISTS user(id INT, name TEXT)");
即使SQL执行出错,也会自动提交或回滚事物,并关闭连接。
4.3 线程锁
import theading
local = threading.Lock()
with lock:
pass
4.4 多个上下文
wiht open("input.txt") as fin, open("output.txt", "w") as fout:
fout.write(fin.read())
5 自定义上下文管理器
5.1 使用类实现
class MyContext:
def __enter__(self):
print("进入上下文")
return "资源对象"
def __exit__(self, exc_type, exc_val, exc_tb):
print("退出上下文,清理资源")
if exc_type:
print("异常类型:", exc_type)
print("异常值:", exc_val)
print("异常追踪:", exc_tb)
return True
return False
with MyContext() as res:
print("使用资源对象:", res)

5.2 使用 contextlib.contextmanager
装饰器
from contextlib import contextmanager
@contextmanager
def my_context_manager():
print('进入上下文')
yield "资源对象"
print('退出上下文,清理资源')
with my_context_manager() as res:
print(f"使用资源: {res}")
这种方式适合简单的上下文管理器编写。
6 面试高频考点
with常考的知识点:
- 本质是上下文管理器协议(
__enter__
和__exit__
)
- 典型应用场景(文件、数据库、锁、网络连接)
- 自定义实现方式(类实现/
contextlib
)
- 异常处理机制(
__exit__
的返回值决定是否吞掉异常)
一句话总结:
with
就是“进入时准备好资源,退出时自动清理,不管中途是否出错,都会自动清理好资源”。
<h2><a id="1__0"></a>1 什么是上下文管理器?</h2>
<p><strong>上下文管理器(Context Manager)</strong> 是一种实现了特定协议的对象,能够在<strong>进入上下文</strong>和<strong>退出上下文</strong>时执行一些操作。</p>
<p>在 Python 中,只要一个对象实现了下面两个方法:</p>
<ul>
<li><code>__enter__(self)</code>:进入上下文时调用。</li>
<li><code>__exit__(self, exc_type, exc_val, exc_tb)</code>:退出上下文时调用(无论是否发生异常都会执行)。</li>
</ul>
<p>它就可以作为上下文管理器被 <code>with</code> 语句使用。</p>
<h2><a id="2__11"></a>2 为什么要使用上下文管理器</h2>
<p>在编程中,我们经常需要对资源进行成对操作,例如:</p>
<ul>
<li>打开文件后,必须关闭。</li>
<li>获取锁后,必须释放。</li>
<li>数据库连接,需要在使用完后关闭。</li>
<li>网络连接,需要断开。</li>
</ul>
<p>如果忘记释放资源,肯呢个会引发内存<strong>泄漏、死锁、文件句柄</strong>耗尽等问题。</p>
<p>上下文管理器可以自动帮我们完成清理工作,即使代码中途抛出异常也不影响。</p>
<h2><a id="3_with__24"></a>3 <code>with</code> 语句的工作原理</h2>
<p>with 语句的基本用法:</p>
<pre><div class="hljs"><code class="lang-shell">with 表达式 [as 变量]:
代码块
</code></div></pre>
<p>底层执行过程等价于:</p>
<pre><div class="hljs"><code class="lang-python">manager = 表达式
exit_method = manager.__exit__
value = manager.__enter__()
<span class="hljs-keyword">try</span>:
代码块
<span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
exit_method(<span class="hljs-built_in">type</span>(e), e, e.__traceback__)
<span class="hljs-keyword">raise</span>
<span class="hljs-keyword">else</span>:
exit_method(<span class="hljs-literal">None</span>, <span class="hljs-literal">None</span>, <span class="hljs-literal">None</span>)
</code></div></pre>
<p>也就是说:</p>
<ul>
<li><code>__enter__()</code> 用于初始化资源,并返回可用对象。</li>
<li><code>__exit__()</code> 用于清理资源,不论是否出现异常都会执行。</li>
</ul>
<h2><a id="4__54"></a>4 常见场景</h2>
<h3><a id="41__56"></a>4.1 文件操作</h3>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-keyword">with</span> <span class="hljs-built_in">open</span>(<span class="hljs-string">"data.txt"</span>, <span class="hljs-string">"r"</span>, encoding=<span class="hljs-string">"utf-8"</span>) <span class="hljs-keyword">as</span> f:
content = f.read()
</code></div></pre>
<p>好处:</p>
<ul>
<li>自动关闭文件</li>
<li>异常安全</li>
</ul>
<h3><a id="42__68"></a>4.2 数据库连接</h3>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-keyword">import</span> sqlite3
<span class="hljs-keyword">with</span> sqlite3.connect(<span class="hljs-string">"test.db"</span>) <span class="hljs-keyword">as</span> conn:
cursor = conn.cursor()
cursor.execute(<span class="hljs-string">"CREATE TABLE IF NOT EXISTS user(id INT, name TEXT)"</span>);
</code></div></pre>
<p>即使SQL执行出错,也会自动提交或回滚事物,并关闭连接。</p>
<h3><a id="43__80"></a>4.3 线程锁</h3>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-keyword">import</span> theading
local = threading.Lock()
<span class="hljs-keyword">with</span> lock:
<span class="hljs-comment"># 临界区代码</span>
<span class="hljs-keyword">pass</span>
<span class="hljs-comment"># 自动释放锁</span>
</code></div></pre>
<h3><a id="44__93"></a>4.4 多个上下文</h3>
<pre><div class="hljs"><code class="lang-python">wiht <span class="hljs-built_in">open</span>(<span class="hljs-string">"input.txt"</span>) <span class="hljs-keyword">as</span> fin, <span class="hljs-built_in">open</span>(<span class="hljs-string">"output.txt"</span>, <span class="hljs-string">"w"</span>) <span class="hljs-keyword">as</span> fout:
fout.write(fin.read())
</code></div></pre>
<h2><a id="5__100"></a>5 自定义上下文管理器</h2>
<h3><a id="51__102"></a>5.1 使用类实现</h3>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-comment"># -*- coding: utf-8 -*-</span>
<span class="hljs-keyword">class</span> <span class="hljs-title class_">MyContext</span>:
<span class="hljs-keyword">def</span> <span class="hljs-title function_">__enter__</span>(<span class="hljs-params">self</span>):
<span class="hljs-built_in">print</span>(<span class="hljs-string">"进入上下文"</span>)
<span class="hljs-keyword">return</span> <span class="hljs-string">"资源对象"</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">__exit__</span>(<span class="hljs-params">self, exc_type, exc_val, exc_tb</span>):
<span class="hljs-built_in">print</span>(<span class="hljs-string">"退出上下文,清理资源"</span>)
<span class="hljs-keyword">if</span> exc_type:
<span class="hljs-built_in">print</span>(<span class="hljs-string">"异常类型:"</span>, exc_type)
<span class="hljs-built_in">print</span>(<span class="hljs-string">"异常值:"</span>, exc_val)
<span class="hljs-built_in">print</span>(<span class="hljs-string">"异常追踪:"</span>, exc_tb)
<span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>
<span class="hljs-keyword">return</span> <span class="hljs-literal">False</span> <span class="hljs-comment"># 返回 False 表示异常会继续抛出</span>
<span class="hljs-keyword">with</span> MyContext() <span class="hljs-keyword">as</span> res:
<span class="hljs-built_in">print</span>(<span class="hljs-string">"使用资源对象:"</span>, res)
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/0c99df67914b705bbf2b0a10746ae51a.png" alt="使用类实现Python上下文管理器" /></p>
<h3><a id="52__contextlibcontextmanager__127"></a>5.2 使用 <code>contextlib.contextmanager</code> 装饰器</h3>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-comment"># -*- coding: utf-8 -*-</span>
<span class="hljs-keyword">from</span> contextlib <span class="hljs-keyword">import</span> contextmanager
<span class="hljs-meta">@contextmanager</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">my_context_manager</span>():
<span class="hljs-built_in">print</span>(<span class="hljs-string">'进入上下文'</span>)
<span class="hljs-keyword">yield</span> <span class="hljs-string">"资源对象"</span>
<span class="hljs-built_in">print</span>(<span class="hljs-string">'退出上下文,清理资源'</span>)
<span class="hljs-keyword">with</span> my_context_manager() <span class="hljs-keyword">as</span> res:
<span class="hljs-built_in">print</span>(<span class="hljs-string">f"使用资源: <span class="hljs-subst">{res}</span>"</span>)
</code></div></pre>
<p>这种方式适合简单的上下文管理器编写。</p>
<h2><a id="6__146"></a>6 面试高频考点</h2>
<p>with常考的知识点:</p>
<ol>
<li>本质是上下文管理器协议(<code>__enter__</code>和<code>__exit__</code>)</li>
<li>典型应用场景(文件、数据库、锁、网络连接)</li>
<li>自定义实现方式(类实现/<code>contextlib</code>)</li>
<li>异常处理机制(<code>__exit__</code>的返回值决定是否吞掉异常)</li>
</ol>
<p>一句话总结:</p>
<p><code>with</code> 就是“进入时准备好资源,退出时自动清理,不管中途是否出错,都会自动清理好资源”。</p>
评论区