博雅钢琴老杨 發表於 2020-3-20 20:05:00

Python中return和yield的区别

<h2>一、说明</h2>
<p>return一直中,每中语言中其没没有很大差别,就不多说了。(shell语言return的是退出状态,可能差别是比较大的,感兴趣可参见“Linux&nbsp;Shell函数定义与调用”)</p>
<p>最早看到yield应该是哪们语言用来调整什么线程优先级的,记不清了,不过那里的yield和python中的yield应该功能有区别。</p>
<p>python中最早看到yield应该是使用scrapy框架写爬虫的时候,之前也有去看yiled的用法,总记不太住。今天又去看了一下,基本上来就是讲些斐波那契数列的烦的要死,自己写段程序研究了一下,这里记一下。</p>
<p>&nbsp;</p>
<h2>二、return和yield的异同</h2>
<p>共同点:return和yield都用来返回值;在一次性地返回所有值场景中return和yield的作用是一样的。</p>
<p>不同点:如果要返回的数据是通过for等循环生成的迭代器类型数据(如列表、元组),return只能在循环外部一次性地返回,yeild则可以在循环内部逐个元素返回。下边我们举例说明这个不同点。</p>
<p>&nbsp;</p>
<h2>三、实例说明</h2>
<h3>3.1 return版本</h3>
<p>示例代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> TestYield:
    </span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> gen_iterator(self):
      result_list </span>=<span style="color: rgba(0, 0, 0, 1)"> []
      </span><span style="color: rgba(0, 0, 255, 1)">for</span> j <span style="color: rgba(0, 0, 255, 1)">in</span> range(3<span style="color: rgba(0, 0, 0, 1)">):
            </span><span style="color: rgba(0, 0, 255, 1)">print</span>(f<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">gen_iterator-{j}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
            result_list.append(j)
      </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> return在循环的外部,待变量完全生成后一次性返回</span>
      <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> result_list

    </span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> call_gen_iterator(self):
      </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 执行下边这句后result_list直接是完成的结果</span>
      result_list =<span style="color: rgba(0, 0, 0, 1)"> self.gen_iterator()
      </span><span style="color: rgba(0, 0, 255, 1)">for</span> i <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> result_list:
            </span><span style="color: rgba(0, 0, 255, 1)">print</span>(f<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">call_gen_iterator-{i}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)

</span><span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(128, 0, 128, 1)">__name__</span> == <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">__main__</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:
    obj </span>=<span style="color: rgba(0, 0, 0, 1)"> TestYield()
    obj.call_gen_iterator()</span></pre>
</div>
<p>执行结果如下,可以看到一次性执行完下层函数,生成完整的迭代器类型返回值result_list,一次性返回给上层函数:</p>
<p><img src="https://img2020.cnblogs.com/i-beta/1116722/202003/1116722-20200320195628198-108706474.png"></p>
<p>&nbsp;</p>
<h3>3.2 yield版本</h3>
<p>示例代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> TestYield:
    </span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> gen_iterator(self):
      </span><span style="color: rgba(0, 0, 255, 1)">for</span> j <span style="color: rgba(0, 0, 255, 1)">in</span> range(3<span style="color: rgba(0, 0, 0, 1)">):
            </span><span style="color: rgba(0, 0, 255, 1)">print</span>(f<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">do_something-{j}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
            </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> yield在for循环内部</span>
            <span style="color: rgba(0, 0, 255, 1)">yield</span><span style="color: rgba(0, 0, 0, 1)"> j

    </span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> call_gen_iterator(self):
      </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> yield并不是直接返回,执行下边这句后result_list什么值都没有</span>
      result_list =<span style="color: rgba(0, 0, 0, 1)"> self.gen_iterator()
      </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> i每请求一个数据,才会触发gen_iterator生成一个数据</span>
      <span style="color: rgba(0, 0, 255, 1)">for</span> i <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> result_list:
            </span><span style="color: rgba(0, 0, 255, 1)">print</span>(f<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">call_gen_iterator-{i}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)

</span><span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(128, 0, 128, 1)">__name__</span> == <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">__main__</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:
    obj </span>=<span style="color: rgba(0, 0, 0, 1)"> TestYield()
    obj.call_gen_iterator()</span></pre>
</div>
<p>执行结果如下,可以看到上下层函数是交替进行的,即上层函数请求迭代一个值下层函数才生成一个值并立即返回这个值:</p>
<p><img src="https://img2020.cnblogs.com/i-beta/1116722/202003/1116722-20200320200437524-120345887.png"></p>
<p>&nbsp;</p>
<h3>3.3&nbsp;yield的意义</h3>
<p>从上边两个小节可以看到,虽然return和yield两者执行的顺序有区别,但整个要做的事情是一样的,所以使用yield并不会比return快,甚至我们可以猜测由于yield总发生上下文切换在速度上还会慢一些,所以速度不是yield的意义。</p>
<p>他们的主要区别是yiled要迭代到哪个元素那个元素才即时地生成,而return要用一个中间变量result_list保存返回值,当result_list的长度很长且每个组成元素内容很大时将会耗费比较大的内存,此时yield相对return才有优势。</p>
<p>&nbsp;</p>
<h2>四、yield和return嵌套使用</h2>
<div class="cnblogs_code"><img src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_61663d5f-b898-40f0-a03b-0757e1b8f0cb" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_61663d5f-b898-40f0-a03b-0757e1b8f0cb" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> TestYield:
    </span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> gen_iterator(self):
      </span><span style="color: rgba(0, 0, 255, 1)">for</span> j <span style="color: rgba(0, 0, 255, 1)">in</span> range(3<span style="color: rgba(0, 0, 0, 1)">):
            </span><span style="color: rgba(0, 0, 255, 1)">print</span>(f<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">do_something-{j}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
            </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> yield在for循环内部</span>
            <span style="color: rgba(0, 0, 255, 1)">yield</span><span style="color: rgba(0, 0, 0, 1)"> j

    </span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> gen_iterator_middle(self):
      </span><span style="color: rgba(0, 0, 255, 1)">print</span>(f<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">gen_iterator_middle</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
      </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 返回的是迭代器的句柄,所以加一层return不影响是可以理解的</span>
      <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> self.gen_iterator()

    </span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> call_gen_iterator(self):
      </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> yield并不是直接返回,执行下边这句后result_list什么值都没有</span>
      result_list =<span style="color: rgba(0, 0, 0, 1)"> self.gen_iterator_middle()
      </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> i每请求一个数据,才会触发gen_iterator生成一个数据</span>
      <span style="color: rgba(0, 0, 255, 1)">for</span> i <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> result_list:
            </span><span style="color: rgba(0, 0, 255, 1)">print</span>(f<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">call_gen_iterator-{i}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)

</span><span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(128, 0, 128, 1)">__name__</span> == <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">__main__</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:
    obj </span>=<span style="color: rgba(0, 0, 0, 1)"> TestYield()
    obj.call_gen_iterator()</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p><img alt="" width="485" height="180" loading="lazy" src="https://img2020.cnblogs.com/blog/1116722/202007/1116722-20200715173536453-1694646399.png"></p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/lsdb/p/12534443.html
頁: [1]
查看完整版本: Python中return和yield的区别