[Python] yield 和 return 有什麼不同?

Posted in :

使用Python很多年常常看到 yield,用這篇文將yield這個關鍵字重點整理一下。覺得整理的比較易懂的是這一篇:

How to Use Generators and yield in Python
https://realpython.com/introduction-to-python-generators/

要列舉 Generators 裡的項目:

letters = ["a", "b", "c", "y"]
it = iter(letters)
while True:
    try:
        letter = next(it)
    except StopIteration:
        break
    print(letter)

也可以用 for 來列舉,會簡單很多:

letters = ["a", "b", "c", "y"]
it = iter(letters)
for letter in it:
    print(letter)

yield 2 次,就可以 next 2 次:

>>> def multi_yield():
...     yield_str = "This will print the first string"
...     yield yield_str
...     yield_str = "This will print the second string"
...     yield yield_str
...
>>> multi_obj = multi_yield()
>>> print(next(multi_obj))
This will print the first string
>>> print(next(multi_obj))
This will print the second string
>>> print(next(multi_obj))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

yield和return一樣會回傳值,不過yield會記住上次執行的位置

yield在下次迭代時會從上次迭代的下一行接續執行,一直執行到下一個yield出現,如果沒有下一個yield則結束這個生成器。

這個神奇例子:

def yield_test(n):
    print("start n =", n)
    for i in range(n):
        yield i*i
        print("i =", i)

    print("end")

tests = yield_test(5)
for test in tests:
    print("test =", test)
    print("--------")

執行結果:

start n = 5
test = 0
--------
i = 0
test = 1
--------
i = 1
test = 4
--------
i = 2
test = 9
--------
i = 3
test = 16
--------
i = 4
end

可以解釋為 遇到 yield 時,程式就會「暫時」被結束返回且相等於 return 會傳回值,但程式本身還保留在記憶體中,等下一次被 next() 呼叫,或 while 與 for 下一個 iter() 時,接續之前 yield 之後的程式碼。

目前我遇到的程式碼在這:
https://github.com/ultrafunkamsterdam/undetected-chromedriver/blob/1c704a71cf4f29181a59ecf19ddff32f1b4fbfc0/undetected_chromedriver/init.py#L716

def find_elements_recursive(self, by, value):
    """
    find elements in all frames
    this is a generator function, which is needed
        since if it would return a list of elements, they
        will be stale on arrival.
    using generator, when the element is returned we are in the correct frame
    to use it directly
    Args:
        by: By
        value: str
    Returns: Generator[webelement.WebElement]
    """
    def search_frame(f=None):
        if not f:
            # ensure we are on main content frame
            self.switch_to.default_content()
        else:
            self.switch_to.frame(f)
        for elem in self.find_elements(by, value):
            yield elem
        # switch back to main content, otherwise we will get StaleElementReferenceException
        self.switch_to.default_content()

    # search root frame
    for elem in search_frame():
        yield elem
    # get iframes
    frames = self.find_elements('css selector', 'iframe')

    # search per frame
    for f in frames:
        for elem in search_frame(f):
            yield elem

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *