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: