9、生成器

生成器

生成器可以理解为一种数据类型,这种数据类型自动实习了迭代器协议(其他的数据类型需要调用自己内置的_iter_()方法),所以生成器就是迭代对象;

生成器解析,对于我们的列表解析来说,只需要简单的包中括号更换成小括号就可以了,它是按需计算的或者说的延迟计算的;

生成器分类及在Python中的表现形式

1、生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果,yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次从这个位置继续往下执行;

2、生成器表达式:类似于列表推导,但是生成器返回按需产生结果一个对象,而不是一次构建一个结果列表;

生成器是一个迭代器,所以我们可以使用next来使用

生成器函数示例:

>>> def gen():

... while True:

... yield 0

... print('...')

...

>>> g=gen()

>>> next(g)

0

>>> next(g)

...

0

生成器的定义和函数类似,但是有yield语句,生成器执行到yield的时候会暂停,在此next会从暂停的地方继续执行

yield弹出值,暂停函数,return返回值,结束函数。

两者是可以一起使用的,并且return也可以结束我们的函数

>>> def gen(x):

... for i in range(10):

... if i == 3:

... return i

... yield i

...

>>> g = gen(10)

>>> for x in g:

... print(x)

...

0

1

2

生成器的计数器的实现

>>> def connt(init):

... c=init

... while True:

... yield c

... c+=1

...

>>> c=connt(0)

>>> next(c)

0

>>> next(c)

1

#!/usr/bin/env python

#

i=1

def test(i):

while True:

yield i

i+=1

t=test(i)

for i in t:

print(i)

生成器的阶乘的实现

>>> def fac():

... ret =1

... idx =1

... while True:

... yield ret

... idx +=1

... ret *= idx

...

>>> f=fac()

>>> next(f)

1

>>> next(f)

2

>>> next(f)

6

>>> next(f)

24

>>> next(f)

120

#!/usr/bin/env python

#

lst=[1,2,3,4]

def func(x):

for i in x:

yield i

res=func(lst)

while True:

print(next(res))

#!/usr/bin/env python

#

def gen(x):

while True:

yield x

x+=1

res=gen(1)

while True:

print(next(res))

yield from lst 等效于 for x in lst; print x

生成器优点

Python使用生气对延迟操作提供了支持,所谓延迟操作,是指在需要的时候才产生结果,而不是立即产生结果,这也是生成器的主要好处;

生成器小结

1、生成器是可迭代对象;

2、实现了延迟计算,省内存;

3、生成器本质和其他的数据类型一样,都是实现了迭代器协议,只不过生成器附加了一个延迟计算省内存的好处;

三元表达式

示例

#!/usr/bin/env python

#

name = 'alex'

print('sb' if name == 'alex' else 'shuaige')

列表解析

# 一般情况下我们需要这样去生成列表

#!/usr/bin/env python

#

lst=[]

for i in range(10):

lst.append('鸡蛋%s'%i)

print(lst)

#三元运算的方式

print(['鸡蛋%s'%i for i in range(10)])

#加入判断语句

print(['鸡蛋%s'%i for i in range(10) if i > 5]) #一元:'鸡蛋%s'%i 二元:for i in range(10) 三元:if i > 5

print(['鸡蛋%s'%i for i in range(10) if i > 5 and i < 8])

#!/usr/bin/env python

#

lst=['鸡蛋%s'%i for i in range(10) if i > 5 and i < 8]

it=lst.__iter__()

print(next(lst.__iter__()))

print(next(lst.__iter__()))

[root@Linux python]# cat day6.py

#!/usr/bin/env python

import os

lst=os.listdir('/var/log')

print([ i for i in lst if str(i).endswith('log')])

[root@Linux python]# python day6.py

['tallylog', 'msg_error.log', 'boot.log', 'cloud-init.log', 'yum.log', 'shadowsocks.log', 'maillog', 'ecs_network_optimization.log', 'ntp.log', 'test2.log', 'test.log', 'lastlog', 'msg_access.log']

#!/usr/bin/env python

#

lst1=[1,2]

lst2=[3,4]

print([(x,y ) for x in lst1 for y in lst2])

列表解析和生成器解析示例

>>> def inc(x):

... print('inc is {0}'.format(x))

... return x + 1

...

>>> inc(1)

inc is 1

2

>>> [ inc(x) for x in range(2) ] #列表解析,直接打印(直接计算)

inc is 0

inc is 1

[1, 2]

>>> ( inc(x) for x in range(2) ) #生成器解析,延迟打印(取值的时候才会计算)

<generator> at 0x7f8f8f729a40>/<generator>

>>> re=( inc(x) for x in range(2) )

>>> next(re)

inc is 0

1

>>>

>>> next(re)

inc is 1

2

示例

def test():

for i in range(4):

yield i

t=test()

for i in t:

print(i)

解析

两者就是一个括号的区别,可以看出,我们的生成器解析,只是在我们从生成器中取值的时候,才会进行计算,而我们的列表解析是直接计算,惰性求值。

next函数用于取出生成器的下一个值

总结

1、把列表解析的[]换成()得到的就是生成器表达式;

2、列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存;

3、Python不但使用迭代器协议,让for循环变得更加通用,大部分内置函数也是使用迭代器协议访问对象的,例如,sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样亿列本值的和:

print(sum([i for i in range(10)]))

print(sum([i ** 2 for i in range(10)]))

print([ x+y for x,y in zip(lst1,lst2) ])

列表解析([])

是将一个可迭代对象(如列表)转换成另一个列表的工具

生成器表达式(())

不创建列表,只是返回一个生成器。这个生成器在每次计算出一个条目后,才把这个条目产生出来。所以在处理大量数据时更有优势


分享到:


相關文章: