Python_生成器generator

生成器generator

  生成器指的是生成器對象,可以由生成器表達式得到,也可以使用yield關鍵字得到一個生成器函數,

  調用這個函數得到一個生成器對象

生成器函數

  函數體中包含yield語句的函數,返回生成器對象

  生成器對象,是一個可迭代對象,是一個迭代器

  生成器對象,是延遲計算、惰性求值的

def inc():
    for i in range(5):
        yield i

print(type(inc))
print(type(inc()))

x = inc()
print(type(x))
print(next(x))

for m in x:
    print(m, '*')

for m in x:
    print(m, '**')

普通的函數調用fn(),函數會立即執行完畢,但是生成器函數可以使用next函數多次執行

生成器函數等價於生成器表達式,只不過生成器函數可以更加複雜


def gen():
    print("line 1")
    yield 1
    print("line 2")
    yield 2
    print("line 3")
    yield 3

next(gen())
next(gen())

g =gen()
print(next(g))
print(next(g))
print(next(g))
print(next(g, 'End'))
print(next(g, 'End'))

總結:

 包含yield語句的生成器函數生成 生成器對象 的時候,生成器函數的函數體不會立即執行;

  next(generator)會從函數的當前位置向後執行到之後碰到的第一個yield語句,會彈出值,並暫停函數執行;

  再次調用next函數,和上一條一樣的處理過程;

  沒有多餘的yield語句能被執行,繼續調用next函數,會拋出StopIteration異常。



生成器應用

  無限循環

def counter():
    i = 0
    while True:
        i += 1
        yield i

def inc(c):
    return next(c)

c = counter()
print(inc(c))
print(inc(c))

計數器:

def inc():
    def counter():
        i = 0
        while True:
            i += 1
            yield i
    c = counter()
    return lambda : next(c)
foo = inc()
print(foo())
print(foo())
處理遞歸問題:

def fib():
    x = 0
    y = 1
    while True:
        yield y
        x, y = y, x+y

foo = fib()
for _ in range(5):
    print(next(foo))

for _ in range(100):
    next(foo)

print(next(foo))


協程coroutine:

  生成器的高級用法;

  比進程、線程輕量級;

  是在用戶空間調試函數的一種實現;

  python3 asyncio就是協程實現,已經加入到標準庫;

  python 3.5 使用async、await關鍵字直接原生支持協程;

  協程調試器實現思路:

    有2個生成器A、B

    next(A)後,A執行到了yield語句暫停,然後去執行next(B),B執行到yield語句也暫停,

    然後再次調用next(A),再調用next(B),周而復始,就實現了調試的效果;

    可以引入調試的策略來實現切換的方式;

  協程是一種非搶佔式調試;



yield from

  yield from是python3.3出現的新的語法;

  yield from iterable 是 for item in iterable: yield item 形式的語法糖;

def inc():
    for x in range(10):
        yield x

foo = inc()
print(next(foo))
print(next(foo))

等價於下面的代碼

def inc():
    yield from range(10)

foo = inc()
print(next(foo))
print(next(foo))

還可以 從可迭代對象中一個個拿元素

def counter(n):
    for x in range(n):
        yield x

def inc(n):
    yield from counter(n)

foo = inc(10)
print(next(foo))
print(next(foo))


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章