[學習總結] python語言學習總結 (二)
1.python中的拆包
之前就只寫了*可以是未知數量的引數,**可以傳入未知數量命名引數。這次詳細記下拆包。
def f1(a, *l): print(a) # 不拆包 print(l) # 拆包 print(*l) f2(l) f2(*l) def f2(*l): print(l) print(*l) def f3(**kw): # 不拆包 print(kw) # 得到鍵名 print(*kw) # 拆包,鍵名對應 f4(**kw)# 注意,python中沒辦法輸出**kw,不信可以自己試試。。 def f4(a, b): print(a, b) f3(a=1, b=2) f1(1, 2, 3) ''' {'a': 1, 'b': 2} a b 1 2 1 (2, 3) 2 3 ((2, 3),) (2, 3) (2, 3) 2 3 '''
我試圖通過這段程式碼的執行情況搞清楚拆包,實際上結果也特別明顯。
其實python給f1和f2函式傳入的引數是個元組,也就是形式引數被轉換為元組傳入了f1和f2中作為實參,這應該是函式給我們做的裝包工作,這個工作對我們在函式裡操作是很方便的,而從未拆包和拆包的f2的輸出來看,我們的理解是正確的。
同樣的,**kw傳入的引數其實是個字典,傳入之後會隱式地進行裝包工作,也就是將a=1,b=2裝包成{'a':1,'b':2}的字典,這樣方便了我們在函式中提取相應引數,我覺得還是很有用的。需要注意的是,我們無法通過print(**kw)得到a=1,b=2的輸出結果,因為print函式貌似不支援這種輸出,可以自己嘗試下。而從f4的輸出看出,我們的理解是正確的。
因此,我們可以在以下場景用到拆包操作。
1.我們有一個元組,想把這個元組的資料分別作為引數傳入。其實就是上面f2函式實現的。
2.我們有一個字典,想把這個字典的資料分別作為引數傳入。其實就是上面f4函式實現的。
2.python中的切片
說實在話,切片用到的次數非常多,因為經常操作字串、list和numpy,所以這個東西用到的次數非常多。
以一個簡單的字串為例
str = "abcdefg" print(str[0:2:1], str[0:2:-1], str[:], str[::-1], str[::-2]) ''' ab abcdefg gfedcba geca '''
切片最常用的是一個左右中括號的操作;通過指定的下標來訪問一組序列的元素,其實就切片操作。
中括號中我們可以指定三個引數,其中第一個引數代表要取的序列的起始index,我們選0,就是從最開始選,第二個引數是結束index,但是不包含這個index對應的資料,從以上輸出中我們是可以看出來的,第三個引數是步長,步長為1,那麼他就從左往右一個一個取;步長為-1,那麼他就從右往左一個一個取,步長為負就是反方向取,因此我們可以填-2,那麼他就從右往左以兩個步長取元素。
其中呢,後面的冒號是可以省略的,也就是可以不填步長,預設就是1,只有一個冒號而不填任何引數就是複製這個序列,而前兩個引數空,只把步長設為1其實就是倒置這個序列。
3.python中的名稱空間
python中的名稱空間我覺得還是要搞清楚的,這樣對理解python這門語言還是很有幫助的。
名稱空間(namespace):名稱空間是名字和物件的對映。也就是可以把一個namespace理解為一個字典,實際上很多當前的Python實現namespace就是用的字典。各個名稱空間是獨立的,沒有任何關係的,所以一個名稱空間中不能有重名,但不同的名稱空間是可以重名而沒有任何影響。
Build-in
....Global
........Enclosed
............Local
可見確實是個層級關係。
我們來分別解釋這四個名稱空間,
Build-in:python直譯器啟動產生的字典,用於存放python內建的名字。
Global:執行python檔案時,存放檔案級定義的名字,就是被import的時候建立,在直譯器退出的時候才被刪除。
Enclosed:指的是一個函式被另一個函式包含時的名稱空間。
Local:執行檔案過程中,呼叫函式時產生的名稱空間,用來存放函式內定義的名字,由於生命週期的原因,函式呼叫結束後該名字會被刪除。
Python在查詢變數時候按照從內至外的順序查詢變數,可以說成是LEGBD順序。
作用域(scope):作用域是Python程式(文字)的某一段或某些段,在這些地方,某個名稱空間中的名字可以被直接引用。這個作用域就是這個名稱空間的作用域。
下面用程式碼來理解一下作用域。
from copy import copy a = 5 print("***build-in and globals***") # print(type(list(globals().keys()))) globals_init = copy(list(globals().keys())) print("\n".join(globals_init)) # 輸出的是build-in的名稱空間下的名字key def f1(b=3): c = 4 print("***globals in f1***", *(globals().keys() - globals_init), sep="\n") # 解釋下這裡,globals().keys()返回的是list,list相減得到的是set,然後對set解包就可以輸出了,也可以把set轉化為list用.join輸出 print("***locals in f1***", *(locals().keys()), sep="\n") def f2(): c = 5 print("***locals in f2***", *(locals().keys()), sep="\n") print("c=", c) f2() print("c=", c) def f3(): nonlocal c c = 6 print("***locals in f3***", *(locals().keys()), sep="\n") print("c=", c) f3() print("c=", c) f1() ''' ***build-in and globals*** __name__ __doc__ __package__ __loader__ __spec__ __annotations__ __builtins__ __file__ __cached__ copy a ***globals in f1*** globals_init f1 ***locals in f1*** b c c= 4 locals in f2 c c= 4 c= 4 locals in f3 c c= 6 '''
咱們從這裡可以看出,不同作用域對應的名稱是相互獨立的,在函式內如果和函式外有相同的變數名稱,會預設把近的那個作為要找到的變數,如果要訪問函式外的比如a怎麼辦呢,很簡單,函式裡面寫上global a 即可,否則你的操作就相當於在函式內的local裡建立了一個新變數。函式巢狀的時候使用nonlocal去操作被套函式外的local變數,甚至也可以通過global操作全域性變數。上面的例子仔細看看應該是理解了。
4.python中的一些高階函式總結
分別是map、filter、reduce、sorted。其中sorted函式之前已經寫過了,但是當時沒有用到引數key,這次查了一下,發現key就是自定義排序規則,比如我們讓key=abs,那麼就會按照絕對值大小排序,當然我們也可以自定義函式,我這裡用lambda定義了匿名函式來對x平方大小排序,然後映射回原list。map函式通過建立一個對映,對後面的range通過呼叫前面的匿名函式形成一個數值對映,然後得到map結果,我們將這個結果轉為list輸出。filter在map的基礎上呢,相當於加上了一層判斷,其實filter也會對後面的list生成一個值的對映,但是filter會利用函式作為引數做一層判斷,保留滿足條件的結果。reduce函式呢,可以允許我們兩兩呼叫函式引數,最終只得到一個結果(如例子),這個例子的計算結果其實是1*2*3*4=24也就是也就是先1*2=2,再2*3=6,再6*4=24的結果。;lambda沒什麼說的了。不是很全,後面會再總結。
from functools import reduce import random a = map(lambda x: x**2, range(1, 5)) print(list(a)) # [1, 4, 9, 16] b = filter(lambda x: x>0, [1,-5,6,0]) print(list(b)) # [1, 6] c = reduce(lambda x,y: x*y,range(1,5)) print(c) # 24 lst = [x * (-1)**x for x in range(1,10)] random.shuffle(lst) print(lst) d = sorted(lst,key = lambda x: x**2,reverse = True) print(d) # [-3, -5, -7, 4, 6, 8, -1, 2, -9] # [-9, 8, -7, 6, -5, 4, -3, 2, -1]