1. 程式人生 > 其它 >打包與解包

打包與解包

Python中的*號使用場景與區別

直白點的區別就是:函式呼叫時,*和都是解包,函式定義時是將傳過來的引數進行打包**

星號的使用場景有兩個

  1. 在【函式定義】和【函式呼叫】的時候使用
  2. 作為接收序列引數:a,*b=1,2,3,4

這裡主要講第一種


函式定義時.

  • args: 接收傳遞過來的序列引用,讀取引用中的位置引數,【打包】成一個元祖,將引用指向args
  • kwargs: 接收傳遞過來的字典引用,讀取引用中的關鍵字引數,【打包】成一個字典,將引用指向kwargs

注意:如果引數列表有*args,**kwargs,但是沒有接收到引數,那麼輸出args就是一個空元祖,kwargs是個空字典,當引數args只有一個時,那麼輸出的元祖就是(1,)後面有一個,代表是個元祖

函式呼叫時

  • *args 和**kwargs:傳遞的是序列的引用,獲取引用中的值,然後作為實參傳遞
  • 注意事項:由於是引用,會更改內部的值,如圖

場景1:函式定義與呼叫都不使用*號

a=[1,2,3,4]
b=(7,8,9,10)
c={'age':18,'name':'vdx'}

def f(tmp):
    print(tmp)
    print(*tmp)  # 這裡面和上面一樣序列解包
f(a)  # 直接傳列表引用作為引數
f(b) # 與函式外面保持一致
f(c) # 與函式外面保持一致
[1, 2, 3, 4]
1 2 3 4
(7, 8, 9, 10)
7 8 9 10
{'age': 18, 'name': 'vdx'}
age name

提問:既然能直接定義一個變數接收序列的引用,為什麼還需要用*和**?

思考:雖然效果是一樣的,但是有些情況不是直接傳列表,而是單個單個的位置引數傳遞,比如fun(1,2,3)


場景2:函式定義時:使用*號

a=[1,2,3,4]
b=(7,8,9,10)
c={'age':18,'name':'vdx'}

def f(*tmp):
    print(tmp)
    print(*tmp)  
f(a)  # 直接傳列表引用作為引數,注意:函式能直接更改原件,如果想弄副本,加上*
f(b) 
f(c)
(1, 2, 3, 4)
1 2 3 4
((7, 8, 9, 10),)
(7, 8, 9, 10)
({'age': 18, 'name': 'vdx'},)
{'age': 18, 'name': 'vdx'}

場景3:函式定義時:使用*號

a=[1,2,3,4]
b=(7,8,9,10)
c={'age':18,'name':'vdx'}

def f(**tmp):
    print(tmp)
f(**c) # 與函式外面保持一致
{'age': 18, 'name': 'vdx'}

提示:對字典使用*,能夠取出裡面的key


為什麼我們不能print(**kwargs),卻能print(*args)

不是說**不能解包,而是print不支援輸出關鍵字引數

區別歸納

1.之前賦值時,*可以用來接收多餘的物件值,那種用法與函式中的用法不一樣,切記混合使用,【一個是賦值時接收多餘的引數,一個是在函式中傳遞,接收多個值是使用】

例題:

# 二、請寫出下列程式碼的執行結果
def f(str1, *args, **kwargs):
    print(str1, args, kwargs)


l = [1, 2, 3]
t = [4, 5, 6]
d = {"a": 7, "b": 8, "c": 9}
f(1, 2)
f(1, 2, 3, "python")
f("python", a=1, b=2, c=3)
f("python", l, d)
f("python", *t)
f('python', *l, **d)
f("python", q="winning", **d)
print('-' * 90)