python有趣的解包用法

python中的解包可以這樣理解:一個list是一個整體,想把list中每個元素當成一個個個體剝離出來,這個過程就是解包,我們來看下面這些例子(分為12個部分)。

1.將list中每個元素賦值給一個變數

>>> name, age, date = [Bob, 20, 2018-1-1]>>> nameBob>>> age20>>> date2018-1-1

2.可迭代對象都可以這樣做

# 列表>>> a,b,c = [a, b, c]>>> aa>>> a,b,c = enumerate([a, b, c])>>> a(0, a)# 元組>>> a,b,c = (a, b, c)>>> aa# 字典>>> a,b,c = {a:1, b:2, c:3}>>> aa>>> a,b,c = {a:1, b:2, c:3}.items()>>> a(a, 1)# 字元串>>> a,b,c = abc>>> aa# 生成器>>> a,b,c = (x + 1 for x in range(3))>>> a1

如果可迭代對象包含的元素和前面待賦值變數數量不一致,則會報錯。但是可以通過*來表示多個元素

3.星號的使用

比如我們要計算平均分,去除最高分和最低分,除了用切片,還可以用解包的方式獲得中間的數值

>>> first, *new, last = [94, 85, 73, 46]>>> new[85, 73]

*來表示多個數值

4.壓包過程

壓包是解包的逆過程,用zip函數實現,下面例子可以對壓包有一個直觀的感受

>>> a = [a, b, c]>>> b = [1, 2, 3]>>> for i in zip(a, b):... print(i)...(a, 1)(b, 2)(c, 3)

5.壓包與解包混合的例子

下面例子實現:兩個列表對應數值相加

>>> a = [0, 1, 2]>>> b = [1, 2, 3]>>> for i, j in zip(a, b):... print(i+j)...135

細細拆解上面過程,可以看出步驟是這樣的

  • 先是zip函數將a b壓包成為一個可迭代對象
  • 對可迭代對象的每一個元素((a, 1))進行解包(i, j = (a, 1)
  • 此時就可以分別調用i j變數進行計算

下面我們加入星號

>>> l = [(Bob, 1990-1-1, 60),... (Mary, 1996-1-4, 50),... (Nancy, 1993-3-1, 55),]>>> for name, *args in l:... print(name, args)...Bob [1990-1-1, 60]Mary [1996-1-4, 50]Nancy [1993-3-1, 55]

6._的用法

當一些元素不用時,用_表示是更好的寫法,可以讓讀代碼的人知道這個元素是不要的

>>> person = (Bob, 20, 50, (11, 20, 2000))>>> name, *_, (*_, year) = person>>> nameBob>>> year2000

7.多變數同時賦值

之前賦值符號右側都是可迭代對象,其實右側也可以是多個變數

>>> a, b = 1, 2>>> a1>>> b2>>> a = 1, 2>>> a(1, 2)

下面用法都會報錯

*a = 1, 2a, b, c = 1, 2

可以這樣

*a, = 1, 2

8.*之可變參數

函數定義時,我們使用*的可變參數,其實也是壓包解包過程

>>> def myfun(*num):... print(num)...>>> myfun(1,2,5,6)(1, 2, 5, 6)

參數用*num表示,num變數就可以當成元組調用了。

其實這個過程相當於*num, = 1,2,5,6

9.*之關鍵字參數

>>> def myfun(**kw):... print(kw)...>>> myfun(name = "Bob", age = 20, weight = 50){weight: 50, name: Bob, age: 20}

鍵值對傳入**kwkw就可以表示相應字典。

**的用法只在函數定義中使用,不能這樣使用

a, **b = {weight: 50, name: Bob, age: 20}

10.可變參數與關鍵字參數的細節問題

(1)函數傳入實參時,可變參數(*)之前的參數不能指定參數名

>>> def myfun(a, *b):... print(a)... print(b)...>>> myfun(a=1, 2,3,4) File "<stdin>", line 1SyntaxError: positional argument follows keyword argument>>> myfun(1, 2,3,4)1(2, 3, 4)

(2)函數傳入實參時,可變參數(*)之後的參數必須指定參數名,否則就會被歸到可變參數之中

>>> def myfun(a, *b, c=None):... print(a)... print(b)... print(c)...>>> myfun(1, 2,3,4)1(2, 3, 4)None>>> myfun(1, 2,3,c=4)1(2, 3)4

如果一個函數想要使用時必須明確指定參數名,可以將所有參數都放在可變參數之後,而可變參數不用管它就可以,也不用命名,如下

>>> def myfun(*, a, b):... print(a)... print(b)...>>> myfun(a = 1,b = 2)12

可變參數的這兩條特性,可以用於將 只需要按照位置賦值的參數 和 需要明確指定參數名的參數區分開來

(3)關鍵字參數都只能作為最後一個參數,前面的參數按照位置賦值還是名稱賦值都可以

下面展示一個既用可變參數有用關鍵字參數的例子

>>> def myfun(a, *b, c, **d):... print(a)... print(b)... print(c)... print(d)...>>> myfun(1, 2, 3, c= 4, m = 5, n = 6)1(2, 3)4{n: 6, m: 5}

(4)可變參數與關鍵詞參數共同使用以表示任意參數

下面是這一點在裝飾器當中的使用

>>> def mydecorator(func):... def wrapper(*args, **kw):... print(I am using a decorator.)... return func(*args, **kw)... return wrapper...>>> @mydecorator... def myfun(a, b):... print(a)... print(b)...>>> myfun(1, b = 2)I am using a decorator.12

(如果有的讀者不熟悉裝飾器,只需要知道,使用@定義myfun相當於myfun = mydecorator(myfun),定義出來的myfun其實是返回結果wrapper函數)

wrapper函數使用*args, **kw作為參數,則被修飾的myfun函數需要的參數無論是什麼樣的,傳入wrapper都不會報錯,這保證了裝飾器可以修飾各種各樣函數的靈活性。畢竟我們一般在函數中傳入參數時,要麼所有參數名都寫,要麼前面幾個不寫,後面的會寫,這樣使用*args, **kw完全沒有問題。

11.解包作為參數傳入函數中

首先定義一個函數

def myfun(a, b): print(a + b)

列表元組的解包

>>> n = [1, 2]>>> myfun(*n)3>>> m = (1, 2)>>> myfun(*m)3

字典的解包

>>> mydict = {a:1, b: 2}>>> myfun(**mydict)3>>> myfun(*mydict)ba

一個應用

>>> bob = {name: Bob, age: 30}>>> "{name}s age is {age}".format(**bob)"Bobs age is 30"

12.多返回值函數

下面過程也涉及到了解包

def myfun(a, b): return a + 1, b + 2>>> m, n = myfun(1, 2)>>> m2>>> n4

其實本身是一個元組

>>> p = myfun(1, 2)>>> p(2, 4)

專欄信息

專欄主頁:python編程

專欄目錄:目錄

版本說明:軟體及包版本說明


推薦閱讀:

TAG:Python | Python開發 | 編程 |