python的生成器对象_深入浅出,谈一谈Python中的生成器对象及其设计原理

朋友们好,前几天发了一篇文章,特地谈了一下Python中的可迭代对象与迭代器对象(

深入浅出,谈一谈Python中的可迭代对象及其迭代原理)。本讲,我想再来深入的谈一下Python中的生成器对象。

1

什么是生成器(generator)

大家知道,Python中一切皆是对象,生成器也不例外。实际上,生成器也是一种迭代器(iterator),它可以看成是迭代器对象的一种特殊情形。例如,通过以下代码我们可以定义一个可迭代对象“MyRange”。

class MyRange:

def __init__(self,stop):

self.stop = stop

self.start = 0

def __iter__(self):

index = 0

while index 

yield index

index += 1

大家可能发现了吧,以上代码中出现了Python中的一个关键字

“yield”。注意,

Python中的yield关键字通常是生成器对象的标志。我们可以通过以下代码利用可迭代对象“

MyRange””生成一个生成器"generate"。

myrange = MyRange(5)

generate = myrange.__iter__()

print(type(generate))

以上代码运行后,可以打印出“generate”变量的类型为

此时,我们就可以像使用迭代器一样来使用生成器来。比如,我们可以利用for循环去迭代遍历这个生成器。

for i in iterator:

print(i)

同时,我们也可以利用迭代器的另一种访问方法来对生成器进行迭代。

while True:

try:

item = generate.__next__()

print(item)

except:

break

以上两种迭代方法的结果都为:

0

1

2

3

4

您可能会问,该生成器的__next__()方法是怎么定义的呢?其实该方法的定义被隐藏了,__next__()方法的函数体实际上就是__iter__()方法的方法体。

2

生成器对象的简化版---生成器函数

前面我们利用可迭代对象“MyRange”生成了一个生成器对象,说明了一个问题,即“生成器对象其实就是一个迭代器对象”。但实际中,我们在利用生成器时,并不会采用以上方法去进行定义。通常我们会通过生成器函数来定义。那么如何利用生成器函数来定义生成器对象呢?我们来看以下代码。

def my_range(n):

i = 0

while i 

yield i

i += 1

请注意,以上代码中出现了一个函数“my_range”。该函数中出现了一个“yield”关键字,实际上,该函数会有一个隐藏的返回值,返回的结果就是一个生成器对象。我们来测试一下。运行以下代码。

print(my_range(5))

结果为

怎么样,明白了吧。我们容易发现,通过此种方法定义的生成器要远远比前面一种的定义方法简单的多。不是吗?

3

生成器对象的遍历的实质

接下来我们来谈一下生成器对象的遍历实质。我们以第二部分中定义的生成器为例。

def my_range(n):

i = 0

while i 

yield i

i += 1

请注意,以上生成器的作用是生成一个从0开始至n-1结束的含有n个整数的生成器对象。接下来,我要遍历该对象。我们说,由于生成器就是一种迭代器,所以,我们就可以采用遍历迭代器的方法来遍历生成器。例如,我们可以用for循环遍历该生成器。

for i in my_range(5):

print(i)

遍历结果为:

0

1

2

3

4

接下里,我们来谈一下其遍历过程的实质。其实,生成器的遍历实质与迭代器的遍历实质类似,它是通过关键字“yield”来实现的。以上代码中,其遍历过程如下:

第一次遍历循环,函数my_range会被执行, 当进入函数体后,程序进入while循环,此时i取0,当遇到yield后,程序会将yield后的i值即0返回,因此,第一次遍历结果为0.

第二次遍历循环,函数my_range会再次被触发, 只不过,它不会从头开始运行,它会从上一次循环的位置继续执行,即执行“i+=1”,此时i 更新为1,然后,继续往下执行while循环,直至再一次遇到“yield”,当遇到yield后,程序会将yield后的i值即1返回,因此,第二次遍历结果为1。

然后以此类推去循环遍历,最终得到的就是以上的结果。

怎么样,明白了吗?您可能会问,这样做有什么好处呢?其实很明显,此种遍历循环,可以借助于yield实现循环一次,计算一次,返回一次。这样,若当遍历的数据较大时,我们可以极大的省去内存的开销。

4

生成器表达式

我们知道,Python是一门“优雅”的编程语言,其特点就是该类语言中总是会出现一些“骚气”的写法,接下来,介绍一下生成器的“骚气”写法----生成器表达式。

生成器表达式与列表推导式和lamnda表达式类似,都是一种简单优雅的简化版写法。我们来介绍一下。还是以以上定义的生成器对象为例。

def my_range(n):

i = 0

while i 

yield i

i += 1

下面,我将其改为利用生成器表达式来定义,具体写法类似于列表推导式.

my_range = (i for i in range(5))

怎么样,简单否,骚气否?

注意,如果想像访问列表一样访问其元素是行不通的。例如:

print(my_range[0])

此时,程序会报出错误。

TypeError: 'generator' object is not subscriptable

此时我们如果想访问该生成器里面的元素,有两种方法:一种可以利用for循环遍历;另一种,则是使用__next__()方法来进行遍历。以下为利用for循环遍历的实例。

for i in my_range:

print(i)

遍历结果为

0

1

2

3

4

-end-

Python 青少年编程

Python教学案例与公益课:

Python微课堂系列:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值