带有yield的函数在Python中被称之为generator(生成器),下面我们将使用斐波那契数列来举例说明下该函数:(环境是在Python3.x下)

 如何生成斐波那契数列:

  斐波那契(Fibonacci)数列是一个简单的递归数列,除第一个数和第二个数外,任意一个数都可由前两个数相加得到。用计算机程序输出斐波那契数列的前N个数是一个非常简单的问题:

  • 版本一:简单输出斐波那契数列前N个数
# -*- coding: utf-8 -*-
# Time : 2019/5/28 14:25
# Author : Eric
# FileName: yield使用浅析.py
# Software: PyCharm
#----------------------------------------------------------------------------------------------------------------------- def fab(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b
n = n + 1
#执行fab(10),我们可以得到如下的输出:
print(fab(10))
1
1
2
3
5
8
13
21
34
55
None

结果是没有问题,但是有经验的开发者会指出,直接在fab函数中有print打印数字会导致该函数可复用性较差,因为fab函数返回None,其他函数无法获得该函数生成的数列。

要提高fab函数的复用性,最好不要直接打印出数列,而是返回一个列表(list)。以下是fab函数改写后的第二个版:

  • 版本二:输出斐波那契数列前N个数
def fab(max):
n, a, b = 0, 0, 1
L = []
while n < max:
L.append(b)
a, b = b, a + b
n = n + 1
return L #可以使用如下方式打印出fab函数返回的List:
for n in fab(10):
print(n) 1
1
2
3
5
8
13
21
34
55

改写后的fab函数通过返回List能满足复用性的要求,但是更有经验的开发者会指出,该函数在运行中占用的内存会随着参数max的增大而增大,如果要控制内存占用,最好不用要List来保存中间结果。

  • 版本三: 使用创建类的的方法来实现
class Fab(object):

    def __init__(self,max):
self.max = max
self.n, self.a, self.b = 0, 0, 1 def __iter__(self):
return self def __next__(self):
if self.n < self.max:
r = self.b
self.a, self.b = self.b, self.a + self.b
self.n = self.n + 1
return r
raise StopIteration()
#Fab类通过__next__()不断返回数列的下一个数,内存占用始终为常数:
for n in Fab(5):
print(n)
1
1
2
3
5

然而,使用class改写的这个版本,代码远远没有第一版的fab函数来得简洁。如果我们想要保持第一版fab函数的简洁性,同时又要获得iterable的效果,yield就派上用场了。

  • 版本四:使用yield的第四版
def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1 #调用第四版的fab和第二版的fab完全一致:
for n in fab(5):
print(n)
1
1
2
3
5

  简单地讲,yield的作用就是把一个函数变成一个generator,带有yield的函数不再是一个普通的函数,Python解释器会将其视为一个generator,调用fab(5)不会执行fab函数,而是返回一个iterable对象!在for循环执行时,每次循环都会执行fab函数内部的代码,执行到yield时,返回函数就会返回一个迭代值,下次迭代时,代码从yield的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到yield。

  yield的好处是显而易见的,把一个函数改写为一个generator就获得了迭代的能力,比起用类的实例保存状态来计算下一个next()的值,不仅代码简介,而且执行流程异常清晰。

  如何判断一个函数是否是一个特殊的generator函数?可以利用isgeneratorfunction判断:

from inspect import isgeneratorfunction
print(isgeneratorfunction(fab)) True

要注意区分fab和fab(5),fab是一个generatorfunction,而fab(5)是调用fab返回的一个generator,好比类的定义和类的实例的区别:

类的定义和类的实例:

import types
print(isinstance(fab,types.GeneratorType))
print(isinstance(fab(5),types.GeneratorType)) False
True

fab是无法迭代的,而fab(5)是可迭代的:

from collections import Iterable
print(isinstance(fab,Iterable))
print(isinstance(fab(5),Iterable))
False
True

  

return的作用

  在一个generator function中,如果没有return,则默认执行至函数完毕,如果在执行过程中return,则直接抛出StopIteration终止迭代。

Python中yield函数浅析的更多相关文章

  1. Python中map()函数浅析

    MapReduce的设计灵感来自于函数式编程,这里不打算提MapReduce,就拿python中的map()函数来学习一下. 文档中的介绍在这里: map(function, iterable, .. ...

  2. Python中int()函数的用法浅析

      int()是Python的一个内部函数 Python系统帮助里面是这么说的 >>> help(int)  Help on class int in module __builti ...

  3. Python中利用函数装饰器实现备忘功能

    Python中利用函数装饰器实现备忘功能 这篇文章主要介绍了Python中利用函数装饰器实现备忘功能,同时还降到了利用装饰器来检查函数的递归.确保参数传递的正确,需要的朋友可以参考下   " ...

  4. [转]Python中yield的解释

    转自: http://python.jobbole.com/83610/ 本文作者: 伯乐在线 - wklken .未经作者许可,禁止转载!欢迎加入伯乐在线 专栏作者. 翻译 来源于stackover ...

  5. Python中yield和yield from的用法

    yield python中yield的用法很像return,都是提供一个返回值,但是yield和return的最大区别在于,return一旦返回,则代码段执行结束,但是yield在返回值以后,会交出C ...

  6. Python中print()函数不换行的方法

    一.让print()函数不换行 在Python中,print()函数默认是换行的.但是,在很多情况下,我们需要不换行的输出(比如在算法竞赛中).那么,在Python中如何做到这一点呢? 其实很简单.只 ...

  7. [翻译]Python中yield的解释

    问题: Python中yield关键字的作用是什么?它做了什么? 例如,我想理解以下代码 def node._get_child_candidates(self, distance, min_dist ...

  8. Python中split()函数的用法及实际使用示例

    Python中split()函数,通常用于将字符串切片并转换为列表. 一.函数说明: split():语法:str.split(str="",num=string.count(st ...

  9. python中range()函数的用法

    python中range()函数可创建一个整数列表,一般用在for循环中. range()函数语法: range(start,stop[,step]) 参数说明: star: 计数从star开始.默认 ...

随机推荐

  1. Bootstrap 垂直(默认)表单

    在建立asp.net mvc视图中,默认的表单是垂直表单,与vs 自动创建的T4模板是水平表单,相比较,没有了<div class="form-horizontal"> ...

  2. C# 反射 设置实体属性

    C# 反射 设置实体属性 http://blog.csdn.net/cestarme/article/details/6548126 C#反射设置属性值和获取属性值 http://www.cnblog ...

  3. bzoj 1680: [Usaco2005 Mar]Yogurt factory【贪心】

    贪心,一边读入一边更新mn,用mn更新答案,mn每次加s #include<iostream> #include<cstdio> using namespace std; in ...

  4. bzoj 1699: [Usaco2007 Jan]Balanced Lineup排队【st表||线段树】

    要求区间取min和max,可以用st表或线段树维护 st表 #include<iostream> #include<cstdio> using namespace std; c ...

  5. hdu1115【多边形求重心模板】

    1.质量集中在顶点上.n个顶点坐标为(xi,yi),质量为mi,则重心(∑( xi×mi ) / ∑mi, ∑( yi×mi ) / ∑mi) 2.质量分布均匀.这个题就是这一类型,算法和上面的不同. ...

  6. (转载)Python一篇学会多线程

    Python 一篇学会多线程 链接:https://www.cnblogs.com/yeayee/p/4952022.html  多线程和多进程是什么自行google补脑,廖雪峰官网也有,但是不够简洁 ...

  7. hdu 2063 过山车 (最大匹配 匈牙利算法模板)

    匈牙利算法是由匈牙利数学家Edmonds于1965年提出,因而得名.匈牙利算法是基于Hall定理中充分性证明的思想,它是部图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最 ...

  8. Service官方教程(8)Bound Service示例之2-跨进程使用Messenger

    Compared to AIDL When you need to perform IPC, using a Messenger for your interface is simpler than ...

  9. 比较C#中几种常见的复制字节数组方法的效率[转]

    [原文链接] 在日常编程过程中,我们可能经常需要Copy各种数组,一般来说有以下几种常见的方法:Array.Copy,IList<T>.Copy,BinaryReader.ReadByte ...

  10. java数组实现买彩票(阿基老师的打乱排序思想)

    package com.wh.array; public class Lottery { public static void main(String[] args) { int[] num=new ...