1 函數(shù)默認(rèn)參數(shù)的陷阱
代碼示例:
def defaultPara(item, l=[]):
l.append(item)
print l
defaultPara('1')
# ['1']
defaultPara('2', ['4', '5'])
# ['4', '5', '2']
defaultPara('3')
# ['1', '3']
上面的第三次調(diào)用,函數(shù)不是使用一個(gè)空數(shù)組作為參數(shù)旱物,而是使用了與第一次調(diào)用時(shí)相同的數(shù)組宵呛。簡(jiǎn)言之,在Python里函數(shù)的默認(rèn)參數(shù)是在函數(shù)定義時(shí)就定義了,而不是在每次調(diào)用函數(shù)時(shí)新生成码秉,因此當(dāng)默認(rèn)參數(shù)為可變參數(shù)時(shí)转砖,其行為可能與我們想象得有出入鲸伴,需要注意。
更加詳細(xì)的討論:Python函數(shù)參數(shù)默認(rèn)值的陷阱和原理深究](http://cenalulu.github.io/python/default-mutable-arguments/)姓赤。
2. GIL
GIL(Global Interpreter Lock)仲吏,是在實(shí)現(xiàn)Python解析器(CPython)時(shí)所引入的一個(gè)概念裹唆。(也就是說它不是python語言的特性,而是實(shí)現(xiàn)解析器(CPython)時(shí)引入的一個(gè)坑)
GIL的存在讓Python看起來只是一個(gè)偽多線程岖食,因?yàn)樗皃revents multiple native threads from executing Python bytecodes at once”舞吭。
Python的多線程在多核CPU上,只對(duì)于IO密集型計(jì)算產(chǎn)生正面效果蔑穴;而當(dāng)有至少有一個(gè)CPU密集型線程存在存和,那么多線程效率會(huì)由于GIL而大幅下降。
更加詳細(xì)的討論:Python的GIL是什么鬼捐腿,多線程性能究竟如何
3. 變長(zhǎng)參數(shù)
當(dāng)函數(shù)的參數(shù)不確定時(shí)茄袖,可以使用*args 和**kwargs嘁锯,如:def myfun1(username, *keys)或def myfun2(username, **keys)等聂薪。
* 用來傳遞任意個(gè)無名字參數(shù)蝗羊,這些參數(shù)會(huì)一個(gè)Tuple的形式訪問;
**用來處理傳遞任意個(gè)有名字的參數(shù)翔悠,這些參數(shù)用dict來訪問涯呻。
4. 類的繼承
MRO:Method Resolution Order
目前采用的是C3算法,它保證了兩點(diǎn):
- 單調(diào)性
C繼承B涝登,B繼承A胀滚,則MRO鏈應(yīng)符合C->B->A的順序 - 重寫問題
# 新式類
class A(object):
def foo(self):
print 'A'
class B(A):
pass
class C(A):
def foo(self):
print 'C'
class D(B, C):
pass
d = D()
d.foo()
# C
可見C3算法保持了DFS和BFS的優(yōu)點(diǎn)乱投。
C3算法:
- L[object] = [object]
- L[C(B1…BN)] = [C] + merge(L[B1]…L[BN], [B1]…[BN])
merge過程:
- 檢查第一個(gè)列表的頭元素(如 L[B1] 的頭)戚炫,記作 H。
- 若 H 未出現(xiàn)在其它列表的尾部施掏,則將其輸出茅糜,并將其從所有列表中刪除蔑赘,然后回到步驟1;否則耙箍,取出下一個(gè)列表的頭部記作 H酥馍,繼續(xù)該步驟。
- 重復(fù)上述步驟卤材,直至列表為空或者不能再找出可以輸出的元素扇丛。如果是前一種情況帆精,則算法結(jié)束;如果是后一種情況卓练,說明無法構(gòu)建繼承關(guān)系襟企,Python 會(huì)拋出異常狮含。
super()
Python的多繼承類是通過MRO的方式來保證各個(gè)父類的函數(shù)被逐一調(diào)用,而且保證每個(gè)父類函數(shù)只調(diào)用一次(如果每個(gè)類都使用super)