日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

[翻译]Python中yield的解释

發布時間:2023/11/28 生活经验 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [翻译]Python中yield的解释 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

問題:

Python中yield關鍵字的作用是什么?它做了什么?

例如,我想理解以下代碼

def node._get_child_candidates(self, distance, min_dist, max_dist):if self._leftchild and distance - max_dist < self._median:yield self._leftchildif self._rightchild and distance + max_dist >= self._median:yield self._rightchild

下面是調用者

result, candidates = list(), [self]
while candidates:node = candidates.pop()distance = node._get_dist(obj)if distance <= max_dist and distance >= min_dist:result.extend(node._values)candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
return result

在_get_child_candidates這個函數被調用時發生了什么?返回了一個列表?還是只返回了一個元素?然后又再次被調用?什么時候調用結束?

這段代碼的來源 Jochen Schulz (jrschulz), who made a great Python library for metric spaces. 完整源碼鏈接:?here


要了解yield的作用,你必須先明白什么是生成器,在此之前,你需要了解什么是可迭代對象(可迭代序列)

迭代

你可以創建一個列表,然后逐一遍歷,這就是迭代

>>> mylist = [1, 2, 3]
>>> for i in mylist:
...    print(i)
1
2
3

mylist是可迭代的對象,當你使用列表解析時,你創建一個列表,即一個可迭代對象

>>> mylist = [x*x for x in range(3)]
>>> for i in mylist:
...    print(i)
0
1
4

任何你可用 “for… in…” 處理的都是可迭代對象:列表,字符串,文件…. 這些迭代對象非常便捷,因為你可以盡可能多地獲取你想要的東西

但,當你有大量數據并把所有值放到內存時,這種處理方式可能不總是你想要的 (but you store all the values in memory and it’s not always what you want when you have a lot of values.)

生成器

生成器是迭代器,但你只能遍歷它一次(iterate over them once) 因為生成器并沒有將所有值放入內存中,而是實時地生成這些值

>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
...    print(i)
0
1
4

這和使用列表解析地唯一區別在于使用()替代了原來的[]

注意,你不能執行for i in mygenerator第二次,因為每個生成器只能被使用一次: 計算0,并不保留結果和狀態,接著計算1,然后計算4,逐一生成

yield

yield是一個關鍵詞,類似return, 不同之處在于,yield返回的是一個生成器

>>> def createGenerator():
...    mylist = range(3)
...    for i in mylist:
...        yield i*i
...
>>> mygenerator = createGenerator() # create a generator
>>> print(mygenerator) # mygenerator is an object!
<generator object createGenerator at 0xb7555c34>
>>> for i in mygenerator:
...     print(i)
0
1
4

這個例子并沒有什么實際作用,僅說明當你知道你的函數將產生大量僅被讀取一次的數據時,使用生成器將是十分有效的做法

要掌握yield,你必須明白 - 當你調用這個函數,函數中你書寫的代碼并沒有執行。這個函數僅僅返回一個生成器對象

這有些狡猾 :-)

然后,在每次for循環使用生成器時,都會執行你的代碼

然后,是比較困難的部分:

第一次函數將會從頭運行,直到遇到yield,然后將返回循環的首個值. 然后,每次調用,都會執行函數中的循環一次,返回下一個值,直到沒有值可以返回

當循環結束,或者不滿足”if/else”條件,導致函數運行但不命中yield關鍵字,此時生成器被認為是空的

問題代碼的解釋

生成器:

# 這你你創建了node的能返回生成器的函數
def node._get_child_candidates(self, distance, min_dist, max_dist):# 這里的代碼你每次使用生成器對象都會調用# 如果node節點存在左子節點,且距離沒問題,返回該節點
if self._leftchild and distance - max_dist < self._median:yield self._leftchild# 同理,返回右子節點
if self._rightchild and distance + max_dist >= self._median:yield self._rightchild# 如果函數運行到這里,生成器空,該節點不存在左右節點

調用者:

# 創建一個空列表,一個包含當前候選對象引用的列表
result, candidates = list(), [self]# 當前候選非空,循環(開始時僅有一個元素)
while candidates:# 從候選列表取出最后一個元素作為當前節點node = candidates.pop()# 獲取obj和當前節點距離distance = node._get_dist(obj)# 如果距離滿足條件,將節點值加入結果列表if distance <= max_dist and distance >= min_dist:result.extend(node._values)# 獲取節點的子節點,加入到候選列表,回到循環開始, 這里使用了生成器candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))# 注意這里extend會反復調用獲取到所有生成器返回值return result

這段代碼包含幾個靈活的部分:

1.這個循環遍讀取歷候選列表,但過程中,候選列表不斷擴展:-)

這是一種遍歷嵌套數據的簡明方法,雖然有些危險,你或許會陷入死循環中

在這個例子中, candidates.extend(node._get_child_candidates(distance, min_dist, max_dist)) 讀取了生成器產生的所有值, 同時while循環產生新的生成器對象加入到列表,因為每個對象作用在不同節點上,所以每個生成器都將生成不同的值

2.列表方法extend() 接收一個生成器,生成器的所有值被添加到列表中

通常,我們傳一個列表作為參數:

>>> a = [1, 2]
>>> b = [3, 4]
>>> a.extend(b)
>>> print(a)
[1, 2, 3, 4]

但是,在代碼中,這個函數接受到一個生成器

這樣的做法好處是:

1.你不需要重復讀這些值

2.你可能有海量的子節點,但是不希望將所有節點放入內存

并且,可以這么傳遞生成器作為參數的原因是,Python不關心參數是一個方法還是一個列表

Python接收可迭代對象,對于字符串,列表,元組還有生成器,都適用!

這就是所謂的“鴨子類型”(duck typing), 這也是Python如此酷的原因之一, 但這是另一個問題了,對于這個問題……

你可以在這里完成閱讀,或者讀一點點生成器的進階用法:

####控制一個生成器的消耗

>>> class Bank(): # let's create a bank, building ATMs
...    crisis = False
...    def create_atm(self):
...        while not self.crisis:
...            yield "$100"
>>> hsbc = Bank() # when everything's ok the ATM gives you as much as you want
>>> corner_street_atm = hsbc.create_atm()
>>> print(corner_street_atm.next())
$100
>>> print(corner_street_atm.next())
$100
>>> print([corner_street_atm.next() for cash in range(5)])
['$100', '$100', '$100', '$100', '$100']
>>> hsbc.crisis = True # crisis is coming, no more money!
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> wall_street_atm = hsbc.create_atm() # it's even true for new ATMs
>>> print(wall_street_atm.next())
<type 'exceptions.StopIteration'>
>>> hsbc.crisis = False # trouble is, even post-crisis the ATM remains empty
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> brand_new_atm = hsbc.create_atm() # build a new one to get back in business
>>> for cash in brand_new_atm:
...    print cash
$100
$100
$100
$100
$100
$100
$100
$100
$100
...

這在很多場景都非常有用,例如控制資源的獲取

Itertools

一個很好的工具

itertools模塊包含很多處理可迭代對象的具體方法. 例如

復制一個生成器?連接兩個生成器?一行將嵌套列表中值分組?不使用另一個列表進行Map/Zip? (Ever wish to duplicate a generator? Chain two generators? Group values in a nested list with a one liner? Map / Zip without creating another list?)

只需要使用itertools模塊

一個例子,4匹馬賽跑的可能抵達順序

>>> horses = [1, 2, 3, 4]
>>> races = itertools.permutations(horses)
>>> print(races)
<itertools.permutations object at 0xb754f1dc>
>>> print(list(itertools.permutations(horses)))
[(1, 2, 3, 4),
(1, 2, 4, 3),
(1, 3, 2, 4),
(1, 3, 4, 2),
(1, 4, 2, 3),
(1, 4, 3, 2),
(2, 1, 3, 4),
(2, 1, 4, 3),
(2, 3, 1, 4),
(2, 3, 4, 1),
(2, 4, 1, 3),
(2, 4, 3, 1),
(3, 1, 2, 4),
(3, 1, 4, 2),
(3, 2, 1, 4),
(3, 2, 4, 1),
(3, 4, 1, 2),
(3, 4, 2, 1),
(4, 1, 2, 3),
(4, 1, 3, 2),
(4, 2, 1, 3),
(4, 2, 3, 1),
(4, 3, 1, 2),
(4, 3, 2, 1)]

了解迭代器的內部機制

迭代過程包含可迭代對象(實現iter()方法) 和迭代器(實現next()方法)

你可以獲取一個迭代器的任何對象都是可迭代對象,迭代器可以讓你迭代遍歷一個可迭代對象(Iterators are objects that let you iterate on iterables.) [好拗口:]

更多關于這個問題的?how does the for loop work

如果你喜歡這個回答,你也許會喜歡我關于?decorators?和?metaclasses?的解釋

總結

以上是生活随笔為你收集整理的[翻译]Python中yield的解释的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。