1 前言
1.1 定义
闭包是指一个函数定义在另一个函数内部,并且引用了外部函数的变量。
当外部函数返回这个内部函数是,这个内部函数就会携带它的自由变量的引用环境,这种行为就称为闭包。
知识点分类:闭包属于 Python 函数式编程和高级函数特性的。
简单理解:
闭包 = 内部函数 + 外部环境变量的引用
1.2 闭包的必要条件
- 必须有一个 嵌套函数 (即内部函数)
- 内部函数必须 引用 外部函数中的变量(自由变量)
- 外部函数返回 内部函数的引用
2 基本案例
def outer(x):
def inner(y):
return x + y
return inner
add = outer(5)
print(add(10))
说明:
x
是自由变量,由 outer
提供。
inner
是一个闭包,记住了 x=5
- 调用
add(10)
实际上就是执行了 5+10
3 闭包的底层原理
内部函数可以访问外部函数的变量*,即使外部函数已经执行完毕。
这是因为 Python 把外部函数的作用于保存在了内部函数的 __closure__
属性中。
def outer(x, a=0):
def inner(y):
return (x + y) * a
return inner
add = outer(5, 2)
print(add.__closure__[0].cell_contents)
print(add.__closure__[1].cell_contents)
print(f"调用结果:{add(10)}")

4 常见应用
4.1 数据封装(模拟私有变量)
def counter():
count = 0
def inc():
nonlocal count
count = count + 1
return count
return inc
c = counter()
print(c())
print(c())
4.2 延迟计算(函数工程)
def make_multiplier(fackor):
def multiply(x):
return x * fackor
return multiply
double = make_multiplier(2)
print(double(10))
4.3 装饰器原理
装饰器的本质也是闭包。
def log(func):
def wrapper(*args, **kwargs):
print(f"正在执行:{func.__name__}")
return func(*args, **kwargs)
return wrapper
@log
def hello(name):
print(f"你好, {name}")
hello("有勇气的牛排")
5 注意点
- 闭包中的变量是共享的,多个闭包共享一个自由变量时需要注意修改冲突。
- 使用
nonloacal
可以在闭包中修改外层变量。
- 闭包容易造成 内存泄漏,尤其在长生命周期中,需要注意引用释放。
6 面试回答
闭包是指一个内部函数引用了外部函数变量,并且外部函数返回了这个内部函数。它使得函数可以记住定义时的环境,即便外部函数已经执行结束。
它通常用于延迟计算、函数封装、函数工厂和装饰器等场景,是函数式编程的重要特性之一。
<h2><a id="1__0"></a>1 前言</h2>
<h3><a id="11__2"></a>1.1 定义</h3>
<p><strong>闭包</strong>是指一个函数<strong>定义在另一个函数内部</strong>,并且<strong>引用了外部函数的变量</strong>。</p>
<p>当外部函数返回这个内部函数是,这个内部函数就会携带它的自由变量的引用环境,这种行为就称为闭包。</p>
<p>知识点分类:闭包属于 <strong>Python 函数式编程</strong>和<strong>高级函数特性</strong>的。</p>
<p>简单理解:</p>
<blockquote>
<p>闭包 = 内部函数 + 外部环境变量的引用</p>
</blockquote>
<h3><a id="12__14"></a>1.2 闭包的必要条件</h3>
<ul>
<li>必须有一个 <strong>嵌套函数</strong> (即内部函数)</li>
<li>内部函数必须 <strong>引用</strong> 外部函数中的变量(自由变量)</li>
<li>外部函数返回 <strong>内部函数的引用</strong></li>
</ul>
<h2><a id="2__20"></a>2 基本案例</h2>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-comment"># -*- coding: utf-8 -*-</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">outer</span>(<span class="hljs-params">x</span>):
<span class="hljs-keyword">def</span> <span class="hljs-title function_">inner</span>(<span class="hljs-params">y</span>):
<span class="hljs-keyword">return</span> x + y
<span class="hljs-keyword">return</span> inner
add = outer(<span class="hljs-number">5</span>)
<span class="hljs-built_in">print</span>(add(<span class="hljs-number">10</span>)) <span class="hljs-comment"># 输出 15</span>
</code></div></pre>
<p>说明:</p>
<ul>
<li><code>x</code> 是自由变量,由 <code>outer</code> 提供。</li>
<li><code>inner</code> 是一个闭包,记住了 <code>x=5</code></li>
<li>调用 <code>add(10)</code> 实际上就是执行了 <code>5+10</code></li>
</ul>
<h2><a id="3__42"></a>3 闭包的底层原理</h2>
<p>内部函数可以访问外部函数的变量*,即使外部函数已经执行完毕。</p>
<p>这是因为 Python 把外部函数的作用于保存在了内部函数的 <code>__closure__</code> 属性中。</p>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-comment"># -*- coding: utf-8 -*-</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">outer</span>(<span class="hljs-params">x, a=<span class="hljs-number">0</span></span>):
<span class="hljs-keyword">def</span> <span class="hljs-title function_">inner</span>(<span class="hljs-params">y</span>):
<span class="hljs-keyword">return</span> (x + y) * a
<span class="hljs-keyword">return</span> inner
add = outer(<span class="hljs-number">5</span>, <span class="hljs-number">2</span>)
<span class="hljs-built_in">print</span>(add.__closure__[<span class="hljs-number">0</span>].cell_contents) <span class="hljs-comment"># 2</span>
<span class="hljs-built_in">print</span>(add.__closure__[<span class="hljs-number">1</span>].cell_contents) <span class="hljs-comment"># 5</span>
<span class="hljs-built_in">print</span>(<span class="hljs-string">f"调用结果:<span class="hljs-subst">{add(<span class="hljs-number">10</span>)}</span>"</span>) <span class="hljs-comment"># 调用结果:30</span>
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/6d920a285556ba25cad134e363592eda.png" alt="image.png" /></p>
<h2><a id="4__66"></a>4 常见应用</h2>
<h3><a id="41__68"></a>4.1 数据封装(模拟私有变量)</h3>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-comment"># -*- coding: utf-8 -*-</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">counter</span>():
count = <span class="hljs-number">0</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">inc</span>():
<span class="hljs-keyword">nonlocal</span> count
count = count + <span class="hljs-number">1</span>
<span class="hljs-keyword">return</span> count
<span class="hljs-keyword">return</span> inc
c = counter()
<span class="hljs-built_in">print</span>(c()) <span class="hljs-comment"># 1</span>
<span class="hljs-built_in">print</span>(c()) <span class="hljs-comment"># 2</span>
</code></div></pre>
<h3><a id="42__88"></a>4.2 延迟计算(函数工程)</h3>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-comment"># -*- coding: utf-8 -*-</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">make_multiplier</span>(<span class="hljs-params">fackor</span>):
<span class="hljs-keyword">def</span> <span class="hljs-title function_">multiply</span>(<span class="hljs-params">x</span>):
<span class="hljs-keyword">return</span> x * fackor
<span class="hljs-keyword">return</span> multiply
double = make_multiplier(<span class="hljs-number">2</span>)
<span class="hljs-built_in">print</span>(double(<span class="hljs-number">10</span>)) <span class="hljs-comment"># 输出 20</span>
</code></div></pre>
<h3><a id="43__103"></a>4.3 装饰器原理</h3>
<p>装饰器的本质也是闭包。</p>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-comment"># -*- coding: utf-8 -*-</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">log</span>(<span class="hljs-params">func</span>):
<span class="hljs-keyword">def</span> <span class="hljs-title function_">wrapper</span>(<span class="hljs-params">*args, **kwargs</span>):
<span class="hljs-built_in">print</span>(<span class="hljs-string">f"正在执行:<span class="hljs-subst">{func.__name__}</span>"</span>)
<span class="hljs-keyword">return</span> func(*args, **kwargs)
<span class="hljs-keyword">return</span> wrapper
<span class="hljs-meta">@log</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">hello</span>(<span class="hljs-params">name</span>):
<span class="hljs-built_in">print</span>(<span class="hljs-string">f"你好, <span class="hljs-subst">{name}</span>"</span>)
hello(<span class="hljs-string">"有勇气的牛排"</span>)
</code></div></pre>
<h2><a id="5__122"></a>5 注意点</h2>
<ul>
<li>闭包中的<strong>变量是共享的</strong>,多个闭包共享一个自由变量时需要注意修改冲突。</li>
<li>使用 <code>nonloacal</code> 可以在闭包中修改外层变量。</li>
<li>闭包容易造成 <strong>内存泄漏</strong>,尤其在长生命周期中,需要注意引用释放。</li>
</ul>
<h2><a id="6__130"></a>6 面试回答</h2>
<p>闭包是指一个内部函数引用了外部函数变量,并且外部函数返回了这个内部函数。它使得函数可以记住定义时的环境,即便外部函数已经执行结束。</p>
<p>它通常用于延迟计算、函数封装、函数工厂和装饰器等场景,是函数式编程的重要特性之一。</p>
评论区