10多萬人關(guān)注的幾個(gè)Python問題
共 6178字,需瀏覽 13分鐘
·
2024-04-15 13:31
本文挑選了StackOverflow上被點(diǎn)贊最多的10個(gè)問題,其中總點(diǎn)贊數(shù)超過了5萬,考慮到很多人只看不點(diǎn)贊,預(yù)估至少有10萬人對(duì)這些問題感興趣!
這么多人點(diǎn)贊,說明兩個(gè)問題:
-
這些問題很常用,編程的時(shí)候經(jīng)常碰到 -
這些問題不簡單,否則不用去網(wǎng)上問
10個(gè)問題,看看你會(huì)幾個(gè)?
-
yield 關(guān)鍵詞是做什么的? -
if name == 'main' 是做什么的 ? -
Python 有三元運(yùn)算符嗎? -
Python 的 metaclasses 是做什么的? -
如果在不出異常的情況下檢查文件是否存在? -
如何一句話合并兩個(gè)字典? -
Python 如何調(diào)用外部命令,比如啟動(dòng)QQ? -
如何安全的創(chuàng)建一個(gè)多層文件夾? -
循環(huán)中如何訪問下標(biāo)? -
staticmethod 和 classmethod 的區(qū)別?
這10個(gè)問題,有的復(fù)雜,有的簡單。你會(huì)幾個(gè)呢?可以在評(píng)論區(qū)留言。
我原本打算講解10個(gè)問題,但由于篇幅原因,本文只涵蓋了被問最多的一個(gè)問題,后續(xù)文章可能會(huì)涵蓋多個(gè)問題。
下面我們重點(diǎn)看第一個(gè)問題:
yield關(guān)鍵詞是做什么的?
這個(gè)問題是所有Python問題的排名第一:
-
有10000多人對(duì)問題點(diǎn)贊,表示有同樣疑問。 -
其中高贊回答有15000多點(diǎn)贊。 -
有超過2百40萬的瀏覽。
問題詳細(xì)內(nèi)容?
Yield關(guān)鍵詞是做什么的?
比如下面的代碼:
def _get_child_candidates(self, distance, min_dist, max_dist):
if self._leftchild and distance - max_dist < self._median:
yield self._leftchild
if self._rightchild and distance + max_dist >= self._median:
yield self._rightchild
這是調(diào)用的代碼:
result, candidates = [], [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
當(dāng)_get_child_candidates被調(diào)用時(shí),發(fā)生了什么?返回了一個(gè)list嗎?還是一個(gè)元素?它會(huì)被反復(fù)調(diào)嗎?后續(xù)調(diào)用什么時(shí)候停止?
看著有點(diǎn)懵?可以繼續(xù)往下看解答,然后再回來看問題。
最高贊回答 (15000多贊)
要理解yield,先理解generators,要理解generators先理解iterable(可迭代的)。
iterables
當(dāng)你創(chuàng)建1個(gè)list,你可以一個(gè)個(gè)讀取它的值,這叫做迭代:
>>> mylist = [1, 2, 3]
>>> for i in mylist:
... print(i)
1
2
3
上面mylist是一個(gè)iterable(可以被迭代的)。當(dāng)你使用一個(gè)列表推導(dǎo)式,你創(chuàng)建了一個(gè)列表,也就是一個(gè)iterable:
>>> mylist = [x*x for x in range(3)]
>>> for i in mylist:
... print(i)
0
1
4
所以可以使用for...in...語法遍歷的就是iterable:list, str, file等等
這些iterable很有用,你可以循環(huán)訪問他們。但是它們所有的值都保存在內(nèi)存中。如果你的list中有10億個(gè)字符串的時(shí)候,創(chuàng)建這個(gè)list會(huì)很慢,而且會(huì)很占用內(nèi)存,所以我們需要genertor.
generators
generator是iterable,可以被循環(huán)。但和上面不一樣,它一般只能被循環(huán)一次。它不會(huì)把所有的值保存在內(nèi)存中,他們?cè)谘h(huán)中動(dòng)態(tài)產(chǎn)生元素的值。
>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
... print(i)
0
1
4
這個(gè)生成器和列表推導(dǎo)式幾乎一樣,唯一區(qū)別使用小括號(hào)(),而不是中括號(hào)[]. 但,你不能兩次使用for i in mygenerator,因?yàn)樯善髦荒鼙谎h(huán)一次:他們計(jì)算0x0,返回結(jié)果,自己并不保存,下一次調(diào)用它,他計(jì)算1x1,以此類推。
yield
yields是一個(gè)關(guān)鍵詞,可以先理解成和return一樣,區(qū)別是它返回一個(gè)generator.
>>> 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
上面這個(gè)例子先創(chuàng)建了range,已經(jīng)占用了內(nèi)存,但平方數(shù)沒有占用。這個(gè)例子不是很好,這是原作者舉的,我的視頻中應(yīng)該有更好的例子。
首先,因?yàn)閥ield的存在,當(dāng)你調(diào)用上面的函數(shù),里面的代碼并沒有執(zhí)行,而不是返回了一個(gè)generator。
然后是關(guān)鍵的地方:
-
當(dāng)for循環(huán)第一次調(diào)用generator的時(shí)候,它會(huì)從頭開始執(zhí)行,直到y(tǒng)ield關(guān)鍵詞,返回第一個(gè)值,也就是0。 -
然后記住執(zhí)行到哪一行代碼,也就是yield的位置。 -
下次for循環(huán)再次調(diào)用它,它從yield的下一行繼續(xù)執(zhí)行,直到再次碰到y(tǒng)ield,返回下一個(gè)值,也就是1. -
這個(gè)過程一直重復(fù),直到generator中沒有內(nèi)容了。例子中就是range里的數(shù)字被用完。
現(xiàn)在再看看最開始的問題:
這是一個(gè)對(duì)樹的遍歷算法,查找樹上符合條件的節(jié)點(diǎn)。代碼中加了詳細(xì)的中文注釋。
generator:
# 這個(gè)函數(shù)會(huì)返回一個(gè)生成器(Generator),這是一個(gè)二叉樹的node對(duì)象中的方法
def _get_child_candidates(self, distance, min_dist, max_dist):
# 如果還有左孩子,并且距離符合條件,返回左孩子,然后暫停在這里
if self._leftchild and distance - max_dist < self._median:
yield self._leftchild
# 如果還有右孩子,并且距離符合條件,返回右孩子,然后暫停在這里
if self._rightchild and distance + max_dist >= self._median:
yield self._rightchild
# 如果執(zhí)行到了這里,說明沒有符合條件的左右孩子了,生成器空了,就迭代結(jié)束了。
caller:
# 創(chuàng)建一個(gè)空的列表,和當(dāng)前對(duì)象節(jié)點(diǎn)
result, candidates = list(), [self]
# 循環(huán),開始里面只有自己
while candidates:
# 彈出最后一個(gè)節(jié)點(diǎn)
node = candidates.pop()
# 獲得obj對(duì)象和目標(biāo)節(jié)點(diǎn)的距離
distance = node._get_dist(obj)
# 如果距離ok,寫入到結(jié)果列表中
if distance <= max_dist and distance >= min_dist:
result.extend(node._values)
# 把自己的子節(jié)點(diǎn)加入到candidates中,這樣循環(huán)會(huì)繼續(xù),直到樹上的所有節(jié)點(diǎn)都被遍歷
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
return result
作者:麥?zhǔn)?/span>
