zoukankan      html  css  js  c++  java
  • 【转两篇】yield 产生器 和 for 包含式

    转自:http://caterpillar.onlyfun.net/Gossip/Python/ForComprehension.html

    你可以在for運算式中使用包含式語法來進行值的收集,for運算結束傳回收集的結果,例如:

    import sys
    files = [arg for arg in sys.argv if arg.endswith('.txt')]
    print(files)


    這個範例可以收集命令列引數中輸入為.txt結尾的檔名,只有符合if測試的arg才會被收集,由於使用[]包含,所以最後的結果是以串列傳回。例如:

    >python demo.py 1.txt 2.doc. 3.txt 4.html 5.txt
    ['1.txt', '3.txt', '5.txt']


    if的部份可以省略,這時會收集所有的迭代的值,你可以在for左邊進行值的處理。例如計算串列中所有數的平方數:

    >>> [number ** 2 for number in [10, 20, 30]]
    [100, 400, 900]


    如果要作更巢狀的元素包括也是可行的,例如以下可將二維矩陣轉換為一維陣列:

    >>> matrix = [
    ...     [1, 2, 3],
    ...     [4, 5, 6],
    ...     [7, 8, 9]
    ... ]
    >>> array = [element for row in matrix for element in row]
    >>> array
    [1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>>


    上例若不以for包含式來實作,則如下:

    >>> matrix = [
    ...     [1, 2, 3],
    ...     [4, 5, 6],
    ...     [7, 8, 9]
    ... ]
    >>> array = []
    >>> for row in matrix:
    ...     for element in row:
    ...         array.append(element)
    ...
    >>> array
    [1, 2, 3, 4, 5, 6, 7, 8, 9]


    另一個例子是,使用for包含式來取得兩個串列的排列組合:

    >>> [letter1 + letter2 for letter1 in 'Justin' for letter2 in 'momor']
    ['Jm', 'Jo', 'Jm', 'Jo', 'Jr', 'um', 'uo', 'um', 'uo', 'ur', 'sm', 'so', 'sm', 'so', 'sr', 'tm', 'to', 'tm', 'to', 'tr', 'im', 'io', 'im', 'io', 'ir', 'nm', 'no
    ', 'nm', 'no', 'nr']
    >>>


    在Python3中,for包含式所收集的元素並不一定得包括在串列中,而可以包括在集合、字典中。例如:

    >>> {i for i in 'Justin'}
    {'i', 'J', 'n', 's', 'u', 't'}
    >>> scores = [('Justin', 95), ('momor', 93), ('Hamimi', 99)]
    >>> {name : score for (name, score) in scores}
    {'Hamimi': 99, 'Justin': 95, 'momor': 93}
    >>>


    如果以()包括for包含式,則會建立一個產生器物件(本身是個具有__next__()的迭代器),可以直接對其迭代來逐一取得元素。例如建立一個質數產生器(參考 Eratosthenes 篩選求 質數):

    import math
    def primes(max):
    prime = [1] * max
    for i in range(2, int(math.sqrt(max))):
    if prime[i] == 1:
    for j in range(2 * i, max):
    if j % i == 0:
    prime[j] = 0
    return (i for i in range(2, max) if prime[i] == 1)

    for prime in primes(1000):
    print(prime, end=" ")




    转自:http://caterpillar.onlyfun.net/Gossip/Python/YieldGenerator.html







    你可以在函式中包括yield來「產生」值,表面上看來,yield就像是return會傳回值,但又不中斷函式的執行:
    >>> def myrange(n):
    ...     x = 0
    ...     while True:
    ...         yield x
    ...         x += 1
    ...         if x == n:
    ...             break
    ...
    >>> for i in myrange(10):
    ...     print(i, end='')
    ... print()
    ...
    0123456789
    >>>


    上面的程式模擬了內建函式range()的作用。表面上看來,你在myrange()函式中使用yield傳回值,然後執行for in迴圈,接著再使用myrange()傳回下一個值,再執行for in迴圈,就好似myrange()執行過後沒有結束似的。

    實際上,在def所定義的本體中,若包括yield運算式,則Python會將之編譯為一個產生器(Generator)。例如:
    >>> myrange(10)
    <generator object myrange at 0x01C98440>
    >>> dir(myrange(10))
    ['__class__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__get
    attribute__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__lt__',
    '__name__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__r
    epr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi
    _code', 'gi_frame', 'gi_running', 'send', 'throw']
    >>>

    產生器物件是個具有迭代器(Iterator)介面的物件,也就是說,它具有__next__()方法,可以使用next()函式來取出下一個值,若無法產生下一個值,則會丟出StopIteration物件。例如:
    >>> g = myrange(3)
    >>> next(g)
    0
    >>> next(g)
    1
    >>> next(g)
    2
    >>> next(g)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
    >>>


    這也就是為何在第一個例子中,在for in迴圈呼叫myrange()會有那樣的結果。一個函式若包括yield,則會傳回產生器物件,而該函式基本上可以包括return,不過不可以指明傳回值(也就是只能傳回None)。return只是用來結束函式的執行流程。例如:
    >>> def myrange(n):
    ...     x = 0
    ...     while True:
    ...         yield x
    ...         return
    ...
    >>> g = myrange(3)
    >>> next(g)
    0
    >>> next(g)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
    >>>

    在上例中,第一個next(g)後,函式的執行流程就因return而結束了,嘗試再執行next(g),就函式定義來看,無法再執行到yield運算式,所以就函式定義來看,StopIteration是因為無法執行到yield運算式而丟出的。

    先前談過 
    for 包含式(Comprehension),實際上,for包含式與迭代器都是一個叫產生器運算式的語言特性。在for 包含式(Comprehension) 中最後一個例子也有提到,使用()與for包含式時,實際上是建立一個產生器。例如:
    >>> (i ** 2 for i in range(3))
    <generator object <genexpr> at 0x01C98440>
    >>> g = (i ** 2 for i in range(3))
    >>> next(g)
    0
    >>> next(g)
    1
    >>> next(g)
    4
    >>> next(g)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
    >>> for p in (i ** 2 for i in range(3)):
    ...     print(p)
    ...
    0
    1
    4
    >>>


    從Python 2.5開始,yield從陳述改為運算式,也就是yield除了「產生」指定的值之外,會有一個運算結果,yield運算結果預設是None,你可以透過產生器的send()方法傳入一個值,這個值就成為yield的運算結果。這給了你一個與產生器溝通的機會。例如:
    >>> def myrange(n):
    ...     x = 0
    ...     while True:
    ...         val = (yield x)
    ...         if val is not None:
    ...             x = val
    ...         else:
    ...             x += 1
    ...         if x >= n:
    ...             break
    ...
    >>> g = myrange(10)
    >>> next(g)
    0
    >>> next(g)
    1
    >>> next(g)
    2
    >>> g.send(0)
    0
    >>> next(g)
    1
    >>> next(g)
    2
    >>> g.send(5)
    5
    >>> next(g)
    6
    >>> next(g)
    7
    >>>






    作者:FreeAquar
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    今天把Oxite给部署起来了!
    PC游戏领域十年间十大败笔
    每天的流水账(2009916)
    小黑颠覆之作 ThinkPad Edge 13真机试用
    向大师们学习Javascript(视频、PPT)
    Google手机Nexus One单挑iPhone、HTC Hero 多图
    福布斯评下一个比尔·盖茨:一半来自中国
    每天的流水账(2009915)
    场地简介
    腾讯品牌形象店即将完工 设计曝光
  • 原文地址:https://www.cnblogs.com/FreeAquar/p/2994042.html
Copyright © 2011-2022 走看看