1 函數默認參數的陷阱
代碼示例:
def defaultPara(item, l=[]):
l.append(item)
print l
defaultPara('1')
# ['1']
defaultPara('2', ['4', '5'])
# ['4', '5', '2']
defaultPara('3')
# ['1', '3']
上面的第三次調用,函數不是使用一個空數組作為參數,而是使用了與第一次調用時相同的數組。簡言之,在Python里函數的默認參數是在函數定義時就定義了,而不是在每次調用函數時新生成,因此當默認參數為可變參數時,其行為可能與我們想象得有出入,需要注意。
更加詳細的討論:Python函數參數默認值的陷阱和原理深究](http://cenalulu.github.io/python/default-mutable-arguments/)。
2. GIL
GIL(Global Interpreter Lock),是在實現Python解析器(CPython)時所引入的一個概念。(也就是說它不是python語言的特性,而是實現解析器(CPython)時引入的一個坑)
GIL的存在讓Python看起來只是一個偽多線程,因為它“prevents multiple native threads from executing Python bytecodes at once”。
Python的多線程在多核CPU上,只對于IO密集型計算產生正面效果;而當有至少有一個CPU密集型線程存在,那么多線程效率會由于GIL而大幅下降。
更加詳細的討論:Python的GIL是什么鬼,多線程性能究竟如何
3. 變長參數
當函數的參數不確定時,可以使用*args 和**kwargs,如:def myfun1(username, *keys)或def myfun2(username, **keys)等。
* 用來傳遞任意個無名字參數,這些參數會一個Tuple的形式訪問;
**用來處理傳遞任意個有名字的參數,這些參數用dict來訪問。
4. 類的繼承
MRO:Method Resolution Order
目前采用的是C3算法,它保證了兩點:
- 單調性
C繼承B,B繼承A,則MRO鏈應符合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的優點。
C3算法:
- L[object] = [object]
- L[C(B1…BN)] = [C] + merge(L[B1]…L[BN], [B1]…[BN])
merge過程:
- 檢查第一個列表的頭元素(如 L[B1] 的頭),記作 H。
- 若 H 未出現在其它列表的尾部,則將其輸出,并將其從所有列表中刪除,然后回到步驟1;否則,取出下一個列表的頭部記作 H,繼續該步驟。
- 重復上述步驟,直至列表為空或者不能再找出可以輸出的元素。如果是前一種情況,則算法結束;如果是后一種情況,說明無法構建繼承關系,Python 會拋出異常。
super()
Python的多繼承類是通過MRO的方式來保證各個父類的函數被逐一調用,而且保證每個父類函數只調用一次(如果每個類都使用super)