Python 生成器

生成器

image

1. 什么是生成器

生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

不同于一般的函数会一次性返回包括了所有数值的数组,生成器一次只能产生一个值,这样消耗的内存数量将大大减小,而且允许调用函数可以很快的处理前几个返回值。

2 创建生成器

生成器可以通过生成器表达式和生成器函数获取到

生成器表达式

创建生成器对象和创建列表生成式特别像

# 创建列表生成式
>>> list_num = [x for x in range(10)]
>>> list_num
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 生成器
>>> glist_num = (x for x in range(10))   # 只需要把中括号换成小括号就成了生成器
>>> glist_num
<generator object <genexpr> at 0x7fc3d7375830>
>>> glist_num.__next__()
0
>>> glist_num.__next__()
1
>>> next(glist_num)
2
>>> next(glist_num)
3

# 生成器表达式内部的代码只有在迭代取值的时候才会执行

使用next()和使用__next__()一样

生成器函数

生成器函数指的是函数体中包含yield关键字的函数

定义生成器函数和定义普通函数一样。

# 1 生成器函数
>>> def my_func():
        print("Hello")
        yield 
    
>>> my_func()
<generator object my_func at 0x7fc3d6c70e08>
>>> res = my_func()
>>> res
<generator object my_func at 0x7fc3d6c70e60>
>>> next(res)
Hello
>>> 
>>> next(res)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

# 生成器函数(yield有返回值)

def my_func():
    print("Hello")
    yield 1

res = my_func()

r = res.__next__()   # 会执行 print("Hello")

print(r)  # r为yield的返回值

# 执行结果:
Hello
1

# 生成器函数(yield多个返回值)
def my_func():
    print("Hello")
    yield 1,2

res = my_func()

r = res.__next__()

print(r)

# 执行结果:
Hello
(1, 2)

#函数中只有一个yield所以只能执行一次__next__()方法
def my_func():
    print("Hello")
    yield 1,2

res = my_func()

print(res.__next__())
print(res.__next__())  # 调用两次就会报错

#执行结果: 
Hello
(1, 2)
Traceback (most recent call last):
  File "b.py", line 8, in <module>
    print(res.__next__())
StopIteration

# 有多个yield
def my_func():
    print("Hello")
    yield 1,2		
    print("world")
    yield 'a','b' 

res = my_func()

print(res.__next__()) # 每执行一个__next__代码往下运行到yield停止 返回后面的数据
print(res.__next__()) # 每执行一个__next__代码往下运行到yield停止 返回后面的数据

注意:当函数体内含有yield关键字 那么在第一次调用函数的时候,并不会执行函数体代码,而是将函数变成了生成器(迭代器).

每执行一个__next__代码往下运行到yield停止 返回后面的数据.

yield不但能返回值,而且还能给它传值

yield传值

使用sendyield传值

示例:

def my_define(name):
    print("%s is doing work" % name)
    while True:
        play  = yield
        print("%s is do %s" %(name, play))


res = my_define("Hans")

res.__next__()
res.__next__()

# 执行结果:
Hans is doing work
Hans is doing None

# 给yield传值:
def my_define(name):
    print("%s is doing work" % name)
    while True:
        play  = yield
        print("%s is do %s" %(name, play))


res = my_define("Hans")

res.__next__()
res.__next__()
# 给yield传两个值:write和coding
res.send("write")
res.send("coding")

# 执行结果:
Hans is doing work
Hans is do None
Hans is do write
Hans is do coding

3 生成器练习

模拟range功能

# 代码
def my_range(start, stop=None, step = 1):
    if not stop:
        stop = start
        start = 0

    while start < stop:
        yield start
        start += step

print("一个参数")
for i in my_range(3):
    print(i)
    
print("两个参数")
for i in my_range(1,3):
    print(i)

print("三个参数")
for i in my_range(1, 10, 2):
    print(i)
# 执行结果:
一个参数
0
1
2
两个参数
1
2
三个参数
1
3
5
7
9

求和(面试题)

# 代码:
def add(n, i):
    return n + i

def test():
    for i in range(4):
        yield i
g = test()
for n in [1, 10]:
    g = (add(n, i) for i in g)
  
res = list(g)
print(res)

#从下面的结果中选择一个:

#A. res=[10,11,12,13]
#B. res=[11,12,13,14]
#C. res=[20,21,22,23]
#D. res=[21,22,23,24]


# 解析:
def add(n, i):
    return n + i
# 调用之前是函数 调用之后是生成器
def test():
    for i in range(4):
        yield i
g = test()  # 初始化生成器对象
for n in [1, 10]:
    g = (add(n, i) for i in g)
    """
    第一次for循环
        g = (add(n, i) for i in g)
    第二次for循环
        g = (add(10, i) for i in (add(10, i) for i in g))
    """
res = list(g)
print(res)

#执行结果为:[20,21,22,23], 答案选C
#A. res=[10,11,12,13]
#B. res=[11,12,13,14]
#C. res=[20,21,22,23]
#D. res=[21,22,23,24]

4 yield和return的区别

yield

  1. 可以返回值(支持多个,并且组织成元组)
  2. 函数体代码遇到yield不会结束而是阻塞
  3. yield可以将函数变成生成器 并且还支持外界传值

return

  1. 可以返回值(支持多个并且组织成元组)
  2. 函数体代码遇到return直接结束

5 生成器和迭代器总结

迭代器对象 生成器对象 我们都可以看成是”工厂”,只有当我们所要数据的时候工厂才会加工出”数据”

主要目的就是节省空间

6. Python中内置函数

image
内置函数
//docs.python.org/zh-cn/3/library/functions.html

Tags: