Python生成器 百日筑基之堵漏

生成器
函数体内有yield选项的就是生成器,生成器的本质是迭代器,由于函数结构和生成器结构类似,可以通过调用判断是函数还是生成器.如下:

def fun():
    yield "我是生成器"
print(fun())

# 打印内容如下:
<generator object fun at 0x0000000002160ED0> 

生成器的优点就是节省内存.
Python获取生成器的二种方式:

  • 通过函数获取生成器
  • 通过生成器推导式创建生成器

通过函数获取生成器

def fun():
    print("fun")
    yield "生成器"
g = fun()
print(g)    # 打印函数名查看是否是生成器 

# 打印内容如下:
<generator object fun at 0x0000000000510ED0> 

从打印内容可以看出是生成器.但是发现生成器里面的内容没有被打印,那如何打印生成器内容呢?我们可以把生成器理解成迭代器的变异版,所以要打印生成器的内容,与迭代器类似,创建生成器对象后.可以使用生成器.__next__()来打印生成器内容.或者next(),send()等来打印生成器,如下:
使用.__next__()来打印生成器中的内容

def fun():
    print("fun")
    yield "生成器"
    print("我在生成器的下面")
g = fun()       # 创建生成器对象
print(g)        # 打印生成器对象
print(g.__next__())    # 打印生成器里面的内容 

# 打印内容如下:
<generator object fun at 0x0000000002200ED0>
fun
生成器 

可以发现yield下面的print语句没有被打印.到yield停止了

def fun():
    print("fun")
    yield "生成器1"
    print("我在生成器1下面")
    yield "生成器2"
    print("我在生成器2的下面")
g = fun()    # 创建生成器对象
print(g.__next__())
print(g.__next__()) 

# 打印内容如下:
fun
生成器1
我在生成器1下面
生成器2 

由上面两个事例可以得出一个总结:就是每next一次就执行一次yield上面的代码一次,yield下面的代码不会被执行,这就是生成器的惰性机制
使用next()打印生成器内容

def fun():
    print("fun")
    yield "生成器"
    print("我在生成器下面")
    yield "生成器2"
    print("我在生成器2的下面")
g = fun()
print(next(g)) # next(g)打印生成器内容
print(next(g)) # next(g)打印生成器内容 

# 打印内容如下:
fun
生成器
我在生成器下面
生成器2 

与.__next__()功能类似
使用send(参数)打印生成器内容:
send方法可以给上一层的yield传递一个值,如果上一个yield没有值的话send的参数将被忽略,如果有值yield的值将被改变成当前的参数,还有需要注意的地方就是如果send(参数)做为第一次迭代,由于上一层没有yield,所以没有办法传参,会导致出现错误,错误内容如下:
TypeError: can‘t send non-None value to a just-started generator
我们将send(None)作为第一次调用即可.然后在第二次调用时可以传适当的参数.
如下:

def fun():
    print("fun")
    val = yield "生成器"
    print("我在生成器下面")
    print(val)
    yield "生成器2"
    print("我在生成器2的下面")
    yield "生成器3"
    print("我在生成器3的下面")
g = fun()
print(g.send(None))
print(g.send("send"))
print(g.send("send2")) 

# 打印内容如下:
fun
生成器
我在生成器下面
send
生成器2
我在生成器2的下面
生成器3 

生成器的基础用法:
使用for循环打印生成器对象

def fun():
    print("fun")
    yield "生成器"
    print("我在生成器下面")
    yield "生成器2"
    print("我在生成器2的下面")
    yield "生成器3"
    print("我在生成器3的下面")
g = fun() # 创建生成器对象
for g_buf in g: # 使用for循环打印生成器对象
    print(g_buf) 

# 打印内容如下
fun
生成器
我在生成器下面
生成器2
我在生成器2的下面
生成器3
我在生成器3的下面

yield可以返回任何数据类型,这里以列表为事例

def fun():
    list_1 = [1,2,3,4,5]
    yield list_1 # 将整个列表作为返回值传给生成器对象
g = fun() # 创建生成器对象
print(g.__next__()) # 打印生成器对象 

# 打印内容如下:
[1, 2, 3, 4, 5] 

如果想要yield从列表中每次返回一个元素使用yield from 列表来实现

def fun():
    list_1 = [1,2,3,4,5]
    yield from list_1
g = fun() # 创建生成器对象
print(g.__next__()) # 打印生成器对象内容 

# 打印内容如下:
1 

可以发现只打印了列表中的一个元素.可以使用for循环打印所有内容:

def fun():
    list_1 = [1,2,3,4,5]
    yield from list_1
g = fun()
for g_buf in g:
print(g_buf) 

# 打印内容如下:
1
2
3
4
5 

相当于事项了5次print(g.__next__()) # 打印生成器对象内容

推导式:
列表推导式:
如给list_1列表赋值1-20,常规做法如下:

list_1 = []
for num in range(20):
    list_1.append(num)
print(list_1) 

# 打印内容如下:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

列表list_1和list_2简单的推导式如下:

list_1 = [num for num in range(20)]
list_2 = ["Python: %s" % num for num in range(5)]
print(list_1)
print(list_2) 

# 打印内容如下:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[‘Python: 0‘, ‘Python: 1‘, ‘Python: 2‘, ‘Python: 3‘, ‘Python: 4‘] 

列表推导式还可以进行筛选,如下:

list_1 = [num for num in range(20) if num < 5 or num == 15]
print(list_1) 

# 打印内容如下:
[0, 1, 2, 3, 4, 15] 

升级一点,将一个嵌套列表中以"a"开头和以"h"开头的元素存放在一个空列表中
基础写法如下:

names = [[‘abc‘, ‘abb‘, ‘zzz‘],["hello","world","xiaoming"]]
list_names = []
for name_1 in names:
    if type(name_1) == list:
        for name_2 in name_1:
            if name_2.startswith("a") or name_2.startswith("h"):
                list_names.append(name_2)
print(list_names) 

# 打印内容如下:
[‘abc‘, ‘abb‘, ‘hello‘]         

使用列表推导法

names = [[‘abc‘, ‘abb‘, ‘zzz‘],["hello","world","xiaoming"]]
list_names = [name_2 for name_1 in names if type(name_1) for name_2 in name_1 if name_2.startswith("a") or\
name_2.startswith("h")] 

# 打印内容如下:
[‘abc‘, ‘abb‘, ‘hello‘] 

生成器推导式:
与列表推导式类似,只不过列表是使用[],生成器推导式使用的是()

g_1 = (num for num in range(20))
print(g_1)
print(g_1.__next__())
print(g_1.__next__()) 

# 打印内容如下:
<generator object <genexpr> at 0x00000000026A0ED0>
0
1 

从打印内容和使用__next__()方法可以看出g_1是列表表达式.
可以使用for循环打印生成器对象

g_1 = (num for num in range(20))
for num in g_1:
  print(num) 

生成器的筛选与列表推导式用法一样,只不过是()
如下:过滤1-20内的所有偶数

g_1 = (num for num in range(20) if num % 2 == 0) 

升级:与上面列表推导式升级练法类似.

names = [[‘abc‘, ‘abb‘, ‘zzz‘],["hello","world","xiaoming"]]
list_names = (name_2 for name_1 in names if type(name_1) for name_2 in name_1 if name_2.startswith("a") or\
name_2.startswith("h")) # 创建生成器对象
print(list_names)
for buf in list_names:
    print(buf) 

# 打印内容下:
<generator object <genexpr> at 0x0000000002150ED0>
abc
abb
hello

生成器表达式和列表推导式的区别:

  • 列表推导式比较耗内存,一次性加载.生成器表达式几乎不占用内存.使用的时候才分配和使用内存
  • 得到的值不一样,列表推导式得到的是一个列表.生成器表达式获取的是一个生成器

字典推导式:

list_1 = ["电视剧","电影"]
list_2 = ["上海滩","黄飞鸿"]
dict_1 = {list_1[i]:list_2[i] for i in range(len(list_1))}
print(dict_1) 

# 打印内容如下:
{‘电视剧‘: ‘上海滩‘, ‘电影‘: ‘黄飞鸿‘} 

集合推导式:
集合的特点;无序,不重复 所以集合推导式自带去重功能

list_1 = [1,2,3,4,2,3,5]
set_1 = {i for i in list_1} # 集合推导式
print(set_1) 

# 打印内容如下:
{1, 2, 3, 4, 5}

总结:

  • 推导式有列表推导式,生成器推导式,字典推导式,集合推导式
  • 生成器表达式: (结果 for 变量 in 可迭代对象 if 条件筛选)
  • 生成器表达式可以直接获取到生成器对象,生成器对象具有惰性,每次只能打印一个生成器内容,可以使用for循环打印生成器所有的内容.

原文地址:https://www.cnblogs.com/caesar-id/p/10316858.html

时间: 2024-10-08 01:10:05

Python生成器 百日筑基之堵漏的相关文章

Python 生成器&迭代器

Python 生成器 带有 yield 的函数在 Python 中被称之为 generator(生成器),用斐波那契数列: def fab(max):     n, a, b = 0, 0, 1     while n < max:         yield b         a, b = b, a + b         n = n + 1 执行: 1 2 3 4 5 6 7 8 9 >>> for n in fab(5):     print n 1 1 2 3 5 简单地

对python生成器特性使用的好例子

1.对序列进行分组的函数(摘自web.py源码utils.py文件中) 1 def group(seq, size): 2 """ 3 Returns an iterator over a series of lists of length size from iterable. 4 5 >>> list(group([1,2,3,4], 2)) 6 [[1, 2], [3, 4]] 7 >>> list(group([1,2,3,4,5]

python生成器(笔记)

Python生成器有些难以用语言表达其概念,所以在这里用几段代码来解释~ 生成器:任何包含yield语句的函数称为生成器; 生成器是一种普通的函数语法定义的迭代器. def test2():     print 9     print 8     yield 7 test2() 上述代码什么都不返回,因为代码碰到了yield函数暂停(或冻结)了,这个暂停同时还影响了yield以上的两个print. def test2():     print 9     print 8     yield 7

Python生成器、迭代器、装饰器

Python迭代器 迭代器是访问集合内元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素都被访问一遍后结束. 迭代器不能回退,只能往前进行迭代.这并不是什么很大的缺点,因为人们几乎不需要在迭代途中进行回退操作. 常用的迭代方法有 .next()方法 for..in..方法 迭代器通俗的理解就是遍历集合内的所有元素 python生成器 这里先说简单的使用,然后再说自己创建生成器 range:生成一个list range(1,5)结果为:[1,2,3,4] xrange:生成一个x

4.Python 生成器yield

常用方法: next    获取下一个值 send    发送值到生成器 throw  发送异常到生成器 python生成器模拟线程并发:

Python 生成器和推导式

一.Python生成器和生成器函数1.生成器和生成器函数的概念    1.生成器的本质是迭代器    2.函数中包含yield,就是生成器函数 2.生成器函数的写法    def func():        a =10        yield 20    gen = func()  #没有执行,而是生成一个生成器    普通函数和生成器函数的不同    1.普通函数名()表示函数的的执行    2.生成器函数名()不是函数的执行,而是生成一个生成器 yield和return的不同    1.

Python 生成器以及应用

一.定义 可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__方法),所以生成器就是可迭代对象 二.生成器的两种形式(Python有两种不同的方式提供生成器) 1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果.yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行 yield的功能: 1 把函数的结果做生迭代器(以一种优雅的方式封装好__iter__,__next__

python 生成器理解

通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了. 所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间.在Python中,这种一边循环一边计算的机制,称为生成器(Generator). 简单生成器 要创建一个generator,有很

Python生成器(yield)

对于调用一个普通的Python函数,一般是从函数的第一行代码开始执行,结束于return语句.异常或者函数所有语句执行完毕.一旦函数将控制权交还给调用者,就意味着全部结束.函数中做的所有工作以及保存在局部变量中的数据都将丢失.再次调用这个函数时,一切都将从头创建.Python是通过生成器来实现类似于协同程序的概念:生成器可以暂时挂起函数,并保留函数的局部变量等数据,然后在再次调用它的时候,从上次暂停的位置继续执行下去. 提高你的 Python:解释 yield 和 Generators(生成器)