1 前言
1.1 定义
- 生成器是一种特殊的迭代器,用
yield
语句或 生成器表达式 创建。
- 不需要手写
__iter__()
和 __nex__()
,Python会自动实现迭代器协议。
yield
会保存函数的执行状态,并在下次迭代时从该位置继续。
yield是一个关键字,可以暂停函数执行(函数挂起),并返回序列值,等被执行到的时候才会取出数据,特别大数据(节省内存)和流式场景。当使用next()、send()函数,即可以从断点处继续执行。
1.2 特点
- 语法简洁:无需类结构即可生成迭代器。
- 惰性求值:按需生成内存,节省内存。
- 可以无限生成:比如斐波那契数列、自然序列。
2 基本案例
2.1 生成器函数
案例1
def my_generator():
yield 1
yield 2
yield 3
gen = my_generator()
for value in gen:
print(value)
案例二
def my_generator():
for i in range(5):
yield i
gen = my_generator()
print(next(gen))
print(next(gen))

2.2 带状态的生成器/状态保留
def countdown(n):
while n > 0:
yield n
n -= 1
for num in countdown(5):
print(num, end=" ")
2.3 生成器表达式
gen_exp = (x * x for x in range(5))
print(next(gen_exp))
print(next(gen_exp))
print(next(gen_exp))
print(next(gen_exp))
print(next(gen_exp))
print(next(gen_exp))
节省内存
案例作用: 循环输出 0 - limit 的数值
常规思路:提前生成放到列表中,或使用range
yield优点:直到执行到的时候,才计算具体值,完全不需要提前计算好值,即可以节省内存。
def generate_numbers(limit):
num = 0
while num < limit:
yield num
num += 1
for num in generate_numbers(1000):
print(num)

3 高级用法 send()
允许外部传入数据
send(value)
可以在生成器暂停时,向其发送一个值。
def echo():
while True:
val = yield
print('echo:', val)
g = echo()
next(g)
g.send('你好:有勇气的牛排')
4 常见场景
- 大文件处理。
- 数据管道(pipeline)中分步生成数据。
- 无限数列生成(斐波那契、自然数、质数)
- 协程基础(早起 Python 协程基于生成器实现)
5 迭代器与生成器的区别
对比项 |
迭代器(Iterator) |
生成器(Generator) |
创建方式 |
类+ __iter__ &__next__ |
yield / 生成器表达式 |
可读性 |
相对繁琐 |
简洁 |
协议实现 |
需要手写 |
自动实现 |
惰性求值 |
✅ |
✅ |
内存占用 |
小 |
更小(天然按需生成) |
使用复杂度 |
高 |
低 |
总结:
在 Python 中,迭代器是实现了 __iter__()
和 __next__
方法的对象,支持惰性求值,可以节省内存。
生成器是迭代器的一种特殊实现,可以用 yield
或生成器表达式创建,语法更简洁,自动保存执行状态,适合处理大数据流火无限序列。
它们共同点是支持按需生成,不同点是生成器更易用、可读性更高。
<h2><a id="1__0"></a>1 前言</h2>
<h3><a id="11__2"></a>1.1 定义</h3>
<ul>
<li>生成器是<strong>一种特殊的迭代器</strong>,用 <code>yield</code> 语句或 <strong>生成器表达式</strong> 创建。</li>
<li>不需要手写 <code>__iter__()</code> 和 <code>__nex__()</code>,Python会自动实现迭代器协议。</li>
<li><code>yield</code> 会保存函数的执行状态,并在下次迭代时从该位置继续。</li>
</ul>
<p>yield是一个关键字,可以暂停函数执行(函数挂起),并返回序列值,等被执行到的时候才会取出数据,特别大数据(节省内存)和流式场景。当使用next()、send()函数,即可以从断点处继续执行。</p>
<h3><a id="12__11"></a>1.2 特点</h3>
<ol>
<li>语法简洁:无需类结构即可生成迭代器。</li>
<li>惰性求值:按需生成内存,节省内存。</li>
<li>可以无限生成:比如斐波那契数列、自然序列。</li>
</ol>
<h2><a id="2__17"></a>2 基本案例</h2>
<h3><a id="21__19"></a>2.1 生成器函数</h3>
<p>案例1</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_">my_generator</span>():
<span class="hljs-keyword">yield</span> <span class="hljs-number">1</span>
<span class="hljs-keyword">yield</span> <span class="hljs-number">2</span>
<span class="hljs-keyword">yield</span> <span class="hljs-number">3</span>
gen = my_generator()
<span class="hljs-keyword">for</span> value <span class="hljs-keyword">in</span> gen:
<span class="hljs-built_in">print</span>(value)
<span class="hljs-comment"># 输出:1 2 3</span>
</code></div></pre>
<p>案例二</p>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">my_generator</span>():
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">5</span>):
<span class="hljs-keyword">yield</span> i
gen = my_generator()
<span class="hljs-built_in">print</span>(<span class="hljs-built_in">next</span>(gen)) <span class="hljs-comment"># 0</span>
<span class="hljs-built_in">print</span>(<span class="hljs-built_in">next</span>(gen)) <span class="hljs-comment"># 1</span>
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/3d2958434cf5976223adc3cf76944a19.png" alt="yield 生成器函数" /></p>
<h3><a id="22__51"></a>2.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_">countdown</span>(<span class="hljs-params">n</span>):
<span class="hljs-keyword">while</span> n > <span class="hljs-number">0</span>:
<span class="hljs-keyword">yield</span> n
n -= <span class="hljs-number">1</span>
<span class="hljs-keyword">for</span> num <span class="hljs-keyword">in</span> countdown(<span class="hljs-number">5</span>):
<span class="hljs-built_in">print</span>(num, end=<span class="hljs-string">" "</span>)
<span class="hljs-comment"># 输出:5 4 3 2 1</span>
</code></div></pre>
<h3><a id="23__66"></a>2.3 生成器表达式</h3>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-comment"># -*- coding: utf-8 -*-</span>
gen_exp = (x * x <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">5</span>))
<span class="hljs-built_in">print</span>(<span class="hljs-built_in">next</span>(gen_exp)) <span class="hljs-comment"># 0</span>
<span class="hljs-built_in">print</span>(<span class="hljs-built_in">next</span>(gen_exp)) <span class="hljs-comment"># 1</span>
<span class="hljs-built_in">print</span>(<span class="hljs-built_in">next</span>(gen_exp)) <span class="hljs-comment"># 4</span>
<span class="hljs-built_in">print</span>(<span class="hljs-built_in">next</span>(gen_exp)) <span class="hljs-comment"># 9</span>
<span class="hljs-built_in">print</span>(<span class="hljs-built_in">next</span>(gen_exp)) <span class="hljs-comment"># 16</span>
<span class="hljs-built_in">print</span>(<span class="hljs-built_in">next</span>(gen_exp)) <span class="hljs-comment"># StopIteration</span>
</code></div></pre>
<h3><a id="_80"></a>节省内存</h3>
<p>案例作用: 循环输出 0 - limit 的数值</p>
<p>常规思路:提前生成放到列表中,或使用range</p>
<p>yield优点:直到执行到的时候,才计算具体值,完全不需要提前计算好值,即可以节省内存。</p>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">generate_numbers</span>(<span class="hljs-params">limit</span>):
num = <span class="hljs-number">0</span>
<span class="hljs-keyword">while</span> num < limit:
<span class="hljs-keyword">yield</span> num
num += <span class="hljs-number">1</span>
<span class="hljs-keyword">for</span> num <span class="hljs-keyword">in</span> generate_numbers(<span class="hljs-number">1000</span>):
<span class="hljs-built_in">print</span>(num) <span class="hljs-comment"># 逐个生成并输出数字</span>
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/037fa636eb076652cc3537b2d5265b48.png" alt="yield节省内存" /></p>
<h2><a id="3__send_101"></a>3 高级用法 send()</h2>
<p>允许外部传入数据</p>
<p><code>send(value)</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_">echo</span>():
<span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
val = <span class="hljs-keyword">yield</span>
<span class="hljs-built_in">print</span>(<span class="hljs-string">'echo:'</span>, val)
g = echo()
<span class="hljs-built_in">next</span>(g) <span class="hljs-comment"># 先启动生成器</span>
g.send(<span class="hljs-string">'你好:有勇气的牛排'</span>)
</code></div></pre>
<h2><a id="4__120"></a>4 常见场景</h2>
<ul>
<li>大文件处理。</li>
<li>数据管道(pipeline)中分步生成数据。</li>
<li>无限数列生成(斐波那契、自然数、质数)</li>
<li>协程基础(早起 Python 协程基于生成器实现)</li>
</ul>
<h2><a id="5__129"></a>5 迭代器与生成器的区别</h2>
<table>
<thead>
<tr>
<th>对比项</th>
<th>迭代器(Iterator)</th>
<th>生成器(Generator)</th>
</tr>
</thead>
<tbody>
<tr>
<td>创建方式</td>
<td>类+ <code>__iter__</code>&<code>__next__</code></td>
<td>yield / 生成器表达式</td>
</tr>
<tr>
<td>可读性</td>
<td>相对繁琐</td>
<td>简洁</td>
</tr>
<tr>
<td>协议实现</td>
<td>需要手写</td>
<td>自动实现</td>
</tr>
<tr>
<td>惰性求值</td>
<td>✅</td>
<td>✅</td>
</tr>
<tr>
<td>内存占用</td>
<td>小</td>
<td>更小(天然按需生成)</td>
</tr>
<tr>
<td>使用复杂度</td>
<td>高</td>
<td>低</td>
</tr>
</tbody>
</table>
<p>总结:</p>
<p>在 Python 中,迭代器是实现了 <code>__iter__()</code> 和 <code>__next__</code> 方法的对象,支持惰性求值,可以节省内存。</p>
<p>生成器是迭代器的一种特殊实现,可以用 <code>yield</code> 或生成器表达式创建,语法更简洁,自动保存执行状态,适合处理大数据流火无限序列。</p>
<p>它们共同点是支持按需生成,不同点是生成器更易用、可读性更高。</p>
评论区