python 重要用法及概念
文章目錄
sorted(iterables, key=lambda, reverse=False)
普通的sorted(iterables)可將list類物件升序排列,如list類物件為多要素物件,則預設根據第一個要素進行排序;
如設reverse可選引數為True,則會降序排列;
在sorted函式可選引數key引數中寫入lambda函式類似於一種模擬排列,即通過lambda函式轉換原iterables中的元素,對轉換後的元素進行排列,並返回該虛擬排列對應的原iterables元素的對映排列
>>> import collections
>>> a = collections.Counter(['a','a','b','c','d','d','d'])
>>> a
Counter({'d': 3, 'a': 2, 'b': 1, 'c': 1})
>>> sorted(a.items(), key=lambda x: x[0])
[('a', 2), ('b', 1), ('c', 1), ('d', 3)]
>>> sorted(a.items(), key=lambda x: x[1] )
[('b', 1), ('c', 1), ('a', 2), ('d', 3)]
注意以上a作為一個dict類的物件,dict類物件無順序因此不可排序,因此選用了.items()方法,該方法將dict類物件轉換成list類物件,該物件的每個要素均為原dict類物件的key和value組成的tuple。上程式碼分別表示以要素第一位置元素排列和第二位置元素排列後的原iterables的元素位置
>>> list1 = [3,5,-4,-1,0,-2,-6]
>>> sorted(list1, key=lambda x: abs(x))
[0, -1, - 2, 3, -4, 5, -6]
zip(a, b, …)
zip函式將其輸入的多個iterables按照各自的index位置進行拆解後將相同位置的要素重組為tuple,返回一個含有多tuple的zip物件;如不同的iterable要素長度或型別不同,重組時將以最短的那個為標準
>>> list(zip([1,2],[2,3],[3,4]))
[(1, 2, 3), (2, 3, 4)]
>>> list(zip([1,2],[2,3],[3,4,5]))
[(1, 2, 3), (2, 3, 4)]
>>> list(zip([1],[2,3],[3,4,5]))
[(1, 2, 3)]
>>> list(zip([(1)],[2,3],[3,4,5]))
[(1, 2, 3)]
>>> list(zip([[(1)],],[2,3],[3,4,5]))
[([1], 2, 3)]
zip(*c)可以將已經拆分重組的tuple list恢復為之前的組合狀態,但是恢復後的各個元素均為tuple
>>> d=zip([1,2],[2,3],[3,4])
>>> list(zip(*d))
[(1, 2), (2, 3), (3, 4)]
作用域
模組對應作用域是global,內層作用域為local,外層作用域為nonlocal。變數查詢順序為:local -> nonlocal -> global -> builtin。
只有class、def和lamda會建立作用域,if,for等語句內部並不會形成local作用域。python讀取變數的時候,如果local作用域沒有該變數,則逐級查詢外層的nonlocal作用域,如仍沒有,則查詢global作用域。在global定義變數時,如果沒有指明nonlocal或global, 就是在區域性作用域定義一個新的變數;當有多層巢狀時nonlocal宣告優先指向最內層的nonlocal作用域。
>>> b = 2
def nonlocal_func():
b = 22
def local_func():
global b
print(b)
return local_func
>>> nonlocal_func()()
2
>>> def nonlocal_func():
b = 22
def local_func():
b = 222
def local_local_func():
nonlocal b
print(b)
return local_local_func
return local_func
>>> nonlocal_func()()()
222
閉包(closure或lexical closure)
通常而言,由class、def和lambda創造的區域性作用域內的變數在其相應的外層作用域是無法訪問的,變數訪問近能自內而外,而不能自外而內,如下所示:
>>> a1 = 1
>>> def func():
a2 = 2
print(a1)
>>> a2
Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name 'a2' is not defined
>>> func()
1
而閉包則是一種特殊現象,即區域性作用域中的變數引數輸入在閉包中實現某種程度的儲存。可以認為在閉包中,方法和資料實現了一定程度的封裝,或者說將資料封裝進了方法之中,這本質上與類是相似的。
由於僅有class、def和lambda可以建立區域性作用域,那麼他們都可以實現閉包的效果,而class本身就是更為高階的封裝,而所有的lambda實現均可以通過def實現,因此下面以lambda為例示意閉包的效果:
>>> def wrapper(a, b):
return lambda x: x * a + b
>>> y = wrapper(1,2)
>>> y
<function wrapper.<locals>.<lambda> at 0x00000248EA95BBF8>
在wrapper函式內部定義lambda函式時lambda函式便形成了一個閉包。正常而言引數a和b都在區域性作用域中,外部無法呼叫和訪問,只能通過呼叫wrapper函式而對a和b進行傳參。將wrapper函式賦給y後,y變成了一個函式
>>> y(1)
3
>>> y(2)
4
>>> y(3)
5
可見對於y的呼叫傳參相當於僅傳入了不同的x值,而a和b的值已經在將wrapper賦給y的時候固化進了y之中。因此區域性作用域中的引數實現了在外部的儲存。a和b此時被稱為自由變數。自由變數即使在其所處區域性作用域函式的生命週期結束以後依然存在(但不可呼叫),因為它被閉包引用了,所以不會被回收。
可用def轉寫上面的例子:
>>> def wrapper(a,b):
def closure(x):
return x * a + b
return closure
>>> y = wrapper(2,3)
>>> y(1)
5
>>> y(2)
7
閉包closure可以被理解為一個只讀的物件,你可以通過外層函式wrapper給其傳遞屬性,如wrapper(2,3),閉包提供給你一個執行的介面。通常在程式中,閉包可幫助我們完成一些通用的功能。