1. 程式人生 > >003---生成器 & 叠代器

003---生成器 & 叠代器

的區別 port lambda 容量 map 只需要 col 裝逼 return

生成器 & 叠代器

列表生成式

現在有個需求,列表[1, 2, 3, 4, 5, 6, 7, 8, 9],將列表裏的每個值加1。

  • 二逼青年版

a = [1, 2, 3, 4, 5, 6, 7, 8, 9]

b = []
for item in a:
    b.append(item + 1)
a = b
print(a)
  • 普通青年版
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]

for index, ele in enumerate(a, 0):
    a[index] += 1

print(a)
  • 文藝版(lambda + map 搭配使用)
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]

a = list(map(lambda x:x+1,a))
print(a)
  • 裝逼青年版
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]

print([i + 1 for i in a])
  • 這種寫法就是列表生成式
  • 習題:利用列表生成式一行代碼實現9 * 9乘法表
print('\n'.join([''.join(['%d * %d = %-3d' % (i, j, i * j) for j in range(1, i + 1)]) for i in range(1, 10)]))

生成器

  • 通過列表生成式,可以直接創建一個列表,但是畢竟內存有限,列表的容量也是有限的。創建一個包含100萬個元素的列表,但是我們僅僅需要訪問前面幾個元素,這就造成了內存大量白白浪費。
  • 在python中有一種更好的解決方式,邊循環邊計算的機制。稱為(generator)
  • 簡單創建生成器(只需要把列表生成器的方括號改成括號)
g = (i for i in range(5))

print(type(g),g.next())
  • next()取值和for循環取值
# 使用next()取值
g = (i for i in range(5))
print(type(g))
print('開始取值')
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
# print(next(g)) # 報錯:StopIteration,因為取不到值了

# 基本上不會使用next(),正確應該使用for循環。而且還不需要擔心會報錯。拿不到函數return返回值
g = (i for i in range(10))
for i in g:
    print(i)
  • 斐波拉契
# 斐波拉契:1 1 2 3 5 8 13 21
def fbi(num):
    n, a, b = 0, 0, 1
    while n < num:
        yield b  # # 到這停止,可以理解為凍結當前代碼。並且,把值返回給外面的next()
        print(a, b)
        a, b = b, a + b
        n += 1


for i in fbi(2):
    print(i)
  • 代碼解析:
    • return 和 yield 的區別
      • 返回並終止函數
      • 返回數據,並凍結當前的執行過程。
      • next()喚醒凍結函數的執行過程,繼續執行,直到遇到下一個yield
    • 函數加了yield之後
      • 函數()就得到了生成器,不next()不開始執行。
      • return 在生成器裏,代表生成器的終止,直接報錯
  • 深入
# 生成器send,相當於喚醒。
def work(n):
    count = 0
    while count < n:
        count += 1
        sign = yield count
        print('sign的值:',sign)
        if not sign:
            yield count + 2


new_range = work(4)
# res = next(new_range)           # 開始第一次取值 拿到一個1
# print(res)                      # 1
# res1 = new_range.send(True)     # 第二次取值 發送一個true  函數遇到true 循環
# print(res1)                     # 2
# res2 = new_range.send(False)    # 第三次取值 n=3
# print(res2)

叠代器

  • 可以作用for循環的類型:
    • 集合類型:str、list、tuple、dict、set
    • generator:生成器和帶yield的函數

    這些類型稱為可叠代對象:iterable
    ```python
    from collections import Iterable

    print(isinstance([],Iterable))
    print(isinstance(‘‘,Iterable))
    print(isinstance({},Iterable))
    print(isinstance(set(),Iterable))
    print(isinstance((i for i in range(2)),Iterable))

    ```

  • 生成器不僅可以作用域for還可以被next()不斷取值,直到沒有數據可取
from collections import Iterator
print(isinstance((i for i in range(2)),Iterator))

總結

  • 凡是可以作用於for循環的對象都是可叠代對象,Iterable
  • 凡是可以作用於next()的對象都是叠代器,Iterator
  • 集合數據類型雖然不是叠代器,但是可以通過iter()函數變成Iterator。

003---生成器 & 叠代器