使用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 之後的程式碼。
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