Python函數參數探索

最近碰到一個問題,就是函數參數類型怎麼判斷,是否就是我們定義函數時就已經確定了的?
def foo(a, b=0, *args, **kwargs):
    print(a)
    print(b)
    print(args)
    print(kwargs)

按照網上資料,普遍的說法

  • 位置參數:a
  • 默認參數:b
  • 接收任意數量位置參數:args
  • 接收任意數量關鍵字參數:kwargs

然後我也一直這麼認爲的,但是事情並沒有這麼簡單,不記得因爲什麼開始對這個參數類型產生了疑惑,遂在網上搜索Python關鍵字參數等相關文章博客,主要有以下幾種形式:

# **kwargs接收任意數量
def foo1(a, b=10, **kwargs):
    pass

def foo2(a):
    pass

def foo3(a, b=10):
    pass

foo1(10, 20, c=30, d=40)
foo2(a=10)
foo3(a=10, b=10)

這個時候我就納悶了,如果一開始函數定義時,參數類型是固定的話,那爲什麼有的文章裏舉例的時候,用到了foo(args1=value1, args2=value2,…)的這種形式,所以我不理解:關鍵字參數不是被**kwargs接收的麼,那爲什麼這種形式也叫關鍵字參數呢? 而我問了一些人之後,有的人說參數類型怎麼會因爲參數傳入形式不同而變化呢?(這個說法應該是有問題的)

後來我查了《Effective Python》中文版的(因爲剛好在手邊),第19條:用關鍵字參數來表達可選的行爲

def foo(a, b, c=30, d=40):
    pass

裏面舉例的時候用到了類似這種形式的函數(簡寫了函數名稱及參數名稱),foo(10,20, c=300, d=400)這種調用方式,這裏c、d書裏說這兩個是可選的關鍵字參數
看到這裏,我明確了一點:關鍵字參數應該不是由**kwargs這種接收方式所決定的

1、函數參數可以按位置或關鍵字來指定
2、…可以使用帶有默認值的關鍵字參數…
3、python函數中的所有位置參數,都可以按關鍵字傳遞

  1. 引用塊內容
def foo(a, b):
    print(a)
    print(b)


foo(b=10, 10)
#    foo(b=10, 10)
#             ^
#SyntaxError: positional argument follows keyword argument

foo(a=10, 10)
#    foo(a=10, 10)
#             ^
#SyntaxError: positional argument follows keyword argument

foo(c=10, 10)
#    foo(c=10, 10)
#             ^
#SyntaxError: positional argument follows keyword argument

看到這裏,有以下幾個可以確認的:

  1. 函數參數有兩種傳入方式:
    a、按位置/按關鍵字,其中按位置就是從前往後,依次接收傳入的參數;
    b、而按關鍵字就是key=value這種形式,這種情況就是指定將value傳給指定的key,如果原函數參數有**kwargs表達式的話,那key可以在原函數中不存在,反之如果沒有**kwargs接收,那就會報錯了
  2. 關鍵字參數後不能有位置參數,如上面幾個調用形式foo(c=10, 10),解釋器報錯時,這條提示信息的優先級高於foo(c=10,d=10) # TypeError: foo() got an unexpected keyword argument 'c'這個錯誤
  3. **kwargs =/= 關鍵字參數,kwargs只是用來接收關鍵字參數,也就是這種(key=value)形式的參數
  4. 當一個參數在前面按位置接收了一個對象後,後面接着以key=value第二次傳入對象時,這裏就會報錯foo(10, a=10) #TypeError: foo() got multiple values for argument 'a'

下面有幾個大膽的推測(尚不確定):

  1. 函數定義時的參數(a, b=10, *args, **kwargs)應該只是用來接受參數的(“容器”)
  2. 參數類型是和傳入方式有關係的,以key=value形式傳入應該都是關鍵字參數

《Python Cookbook 3》中有一個例子-強制接收關鍵字

# python3,據說python2不支持,擁抱python3,和python2saygoodbye吧!
def foo(a, b, *, c, d):
    pass
foo(10, b=10, ... , c=30, d=40)

這個例子裏面,調用函數時傳入的參數(c、d)必須以key=value的形式傳入,所以前面的推測應該是對的

總結:
1、函數定義時定義的是參數名稱,不是參數類型,參數類型是由傳入方式決定的
2、默認參數也叫可選關鍵字參數,這種類型比較特殊,因爲一開始函數定義時就以key=value的形式讓key指向value了
3、知道怎麼處理參數就好了,對這些概念不要過於糾結
4、以上內容只是個人想法,可能有的地方理解錯誤,希望知道的網友能指點迷津

發佈了35 篇原創文章 · 獲贊 7 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章