国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

python中的yield使用詳解

CntChen / 2668人閱讀

摘要:是的一個關鍵字,剛接觸的時候對這個關鍵字一知半解,掌握之后才發現這關鍵字有大用,本文將對的使用方法好好梳理一番。使用創建生成器在中,生成器是一種可迭代對象,但可迭代對象不一定是生成器。

yield是python的一個關鍵字,剛接觸python的時候對這個關鍵字一知半解,掌握之后才發現這關鍵字有大用,本文將對yield的使用方法好好梳理一番。

1 使用yield創建生成器

在python中,生成器是一種可迭代對象,但可迭代對象不一定是生成器。
例如,list就是一個可迭代對象

>>> a = list(range(3))
>>> for i in a:
    print(i)

0
1
2
3

但是一個list對象所有的值都是放在內存中的,如果數據量非常大的話,內存就有可能不夠用;這種情況下,就可以生成器,例如,python可以用“()”構建生成器對象:

>>> b = (x for x in range(3))
>>> for i in b:
    print(i)

0
1
2
>>> for i in b:
    print(i)
    
>>> 

生成器可以迭代的,并且數據實時生成,不會全部保存在內存中;值得注意的是,生成器只能讀取一次,從上面的運行結果可以看到,第二次for循環輸出的結果為空

在實際編程中,如果一個函數需要產生一段序列化的數據,最簡單的方法是將所有結果都放在一個list里返回,如果數據量很大的話,應該考慮用生成器來改寫直接返回列表的函數(Effective Python, Item 16).

>>> def get_generator():
    for i in range(3):
        print("gen ", i)
        yield i
        
>>> c = get_generator()    
>>> c = get_generator()
>>> for i in c:
    print(i)
    
gen  0
0
gen  1
1
gen  2
2

由上面的代碼可以看出,當調用get_generator函數時,并不會執行函數內部的代碼,而是返回了一個迭代器對象,在用for循環進行迭代的時候,函數中的代碼才會被執行。
除了使用for循環獲得生成器返回的值,還可以使用next和send

>>> c = get_generator()
>>> print(next(c))
gen  0
0
>>> print(next(c))
gen  1
1
>>> print(next(c))
gen  2
2
>>> print(next(c))
Traceback (most recent call last):
  File "", line 1, in 
    print(next(c))
StopIteration
>>> c = get_generator()
>>> c.send(None)
gen  0
0
>>> c.send(None)
gen  1
1
>>> c.send(None)
gen  2
2
>>> c.send(None)
Traceback (most recent call last):
  File "", line 1, in 
    c.send(None)
StopIteration

生成器的結果讀取完后,會產生一個StopIteration的異常

2 coroutines中使用

yield一個常見的使用場景是通過yield來實現協程,已下面這個生產者消費者模型為例:

def consumer():
    r = "yield"
    while True:
        print("[CONSUMER] r is %s..." % r)
        #當下邊語句執行時,先執行yield r,然后consumer暫停,此時賦值運算還未進行
        #等到producer調用send()時,send()的參數作為yield r表達式的值賦給等號左邊
        n = yield r #yield表達式可以接收send()發出的參數
        if not n:
            return # 這里會raise一個StopIteration
        print("[CONSUMER] Consuming %s..." % n)
        r = "200 OK"

def produce(c):
    c.send(None)
    n = 0
    while n < 5:
        n = n + 1
        print("[PRODUCER] Producing %s..." % n)
        r = c.send(n)   #調用consumer生成器
        print("[PRODUCER] Consumer return: %s" % r)
    c.send(None)    
    c.close()

c = consumer()
produce(c)
[CONSUMER] r is yield...
[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
[CONSUMER] r is 200 OK...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
[CONSUMER] r is 200 OK...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 3...
[CONSUMER] Consuming 3...
[CONSUMER] r is 200 OK...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 4...
[CONSUMER] Consuming 4...
[CONSUMER] r is 200 OK...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 5...
[CONSUMER] Consuming 5...
[CONSUMER] r is 200 OK...
[PRODUCER] Consumer return: 200 OK
Traceback (most recent call last):
  File ".foobar.py", line 51, in 
    produce(c)
  File ".foobar.py", line 47, in produce
    c.send(None)
StopIteration

在上面的例子中可以看到,yield表達式與send配合,可以起到交換數據的效果,

n = yield r

r = c.send(n)
3 contextmanager中使用

另外一個比較有意思的使用場景是在contextmanager中,如下:

import logging
import contextlib

def foobar():
    logging.debug("Some debug data")
    logging.error("Some error data")
    logging.debug("More debug data")


@contextlib.contextmanager
def debug_logging(level):
    logger = logging.getLogger()
    old_level = logger.getEffectiveLevel()
    logger.setLevel(level)
    try:
        yield #這里表示with塊中的語句
    finally:
        logger.setLevel(old_level)


with debug_logging(logging.DEBUG):
    print("inside context")
    foobar()
print("outside context")
foobar()
inside context
DEBUG:root:Some debug data
ERROR:root:Some error data
DEBUG:root:More debug data
outside context
ERROR:root:Some error data

在上面的代碼中,通過使用上下文管理器(contextmanager)來臨時提升了日志的等級,yield表示with塊中的語句;

總結

yield表達式可以創建生成器,應該考慮使用生成器來改寫直接返回list的函數;

由于生成器只能讀取一次,因此使用for循環遍歷的時候要格外注意;生成器讀取完后繼續讀的話會raise一個StopIteration的異常,實際編程中可以使用這個異常來作為讀取終止的判斷依據;

yield一個常見的使用場景是實現協程;通過與send函數的配合,可以起到交換數據的效果;

yield還可以在contextmanager修飾的函數中表示with塊中的語句;

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/42808.html

相關文章

  • pythonyield的用法詳解——最簡單,最清晰的解釋

    摘要:程序執行,程序會從關鍵字那一行繼續向下運行,會把這個值賦值給變量由于方法中包含方法,所以程序會繼續向下運行執行方法,然后再次進入循環程序執行再次遇到關鍵字,會返回后面的值后,程序再次暫停,直到再次調用方法或方法。 此文轉載,侵刪,原文地址:https://blog.csdn.net/mieleiz... 首先,如果你還沒有對yield有個初步分認識,那么你先把yield看做return...

    VPointer 評論0 收藏0
  • 分布式計算框架MapReduce

    1 MapReduce概念 和 MapReduce編程模型什么是MapReduce源于Google的MapReduce論文(2004年12月)Hadoop的MapReduce是Google論文的開源實現MapReduce優點: 海量數據離線處理&易開發MapReduce缺點: 實時流式計算MapReduce分而治之的思想數錢實例:一堆鈔票,各種面值分別是多少單點策略一個人數所有的鈔票,數出各種面值...

    Tecode 評論0 收藏0
  • Python裝飾器的另類用法

    摘要:今天我們一起探討一下裝飾器的另類用法。語法回顧開始之前我們再將裝飾器的語法回顧一下。例子本身只是演示了裝飾器的一種用法,但不是推薦你就這樣使用裝飾器。類裝飾器在以前,還不支持類裝飾器。 之前有比較系統介紹過Python的裝飾器(請查閱《詳解Python裝飾器》),本文算是一個補充。今天我們一起探討一下裝飾器的另類用法。 語法回顧 開始之前我們再將Python裝飾器的語法回顧一下。 @d...

    hqman 評論0 收藏0
  • redux-saga框架使用詳解及Demo教程

    摘要:通過創建將所有的異步操作邏輯收集在一個地方集中處理,可以用來代替中間件。 redux-saga框架使用詳解及Demo教程 前面我們講解過redux框架和dva框架的基本使用,因為dva框架中effects模塊設計到了redux-saga中的知識點,可能有的同學們會用dva框架,但是對redux-saga又不是很熟悉,今天我們就來簡單的講解下saga框架的主要API和如何配合redux框...

    Nosee 評論0 收藏0

發表評論

0條評論

CntChen

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<