1. 程式人生 > >Python函數參數學習筆記

Python函數參數學習筆記

列表 依次 多任務 HA 拷貝 都是 符號 pan student

在學習python函數參數的時候,發現python函數有多種參數形式,感覺有必要記錄一下,弄懂它們之間的區別和使用,主要參考了廖雪峰的python基礎教程:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431752945034eb82ac80a3e64b9bb4929b16eeed1eb9000

1、位置參數

例如:求xn

def power(x, n):
    s = 1
    while n > 0:
        n = n - 1
        s *= x
    print(s)


power(
3, 4) # 81 power(4, 3) # 64

可見,調用函數時,傳入的值按照順序依次賦給了x、n

在調用函數的時候,有多少個位置參數,就必須傳入多少個值,否則會報錯

power(3)
TypeError: power() missing 1 required positional argument: ‘n‘

提示power()函數缺少1個需要的位置參數‘n‘,從這兒也可以看出,位置參數是依次傳值的

2、默認參數

默認參數:在函數定義的時候,直接指定參數的值

def power(x, n=2):
    s = 1
    while n > 0:
        n 
= n - 1 s *= x print(s)

在本例中,power()函數給定了默認參數n=2,這種情況下,如果我們僅僅需要調用power()函數求一個數x的平方,在調用該函數時,就可以只傳入x的值

power(3)  # 9

如果我們想調用power()函數求x的4、5、6...次方的話,就可以通過給默認參數傳入值的方式

power(3, 4)  # 81

可見,默認參數能夠簡化函數的調用,這在一個函數的某些參數在多數情況下不需要改變時非常有用。比如:打印一個班級學生的姓名(name),年齡(age)和籍貫(city)信息

通常來講,一個班級的同學的籍貫都是同一地區的,如果每次調用都要傳入city參數,會使調用變得復雜,這個時候,可以將city參數設置成默認參數

def student(name, age, city=chongqing):
    print(name:, name)
    print(age:, age)
    print(city:, city)


student(fzp, 7)

輸入結果:

name: fzp
age: 7
city: chongqing

設置默認參數時,需要註意一下幾點:

  1)必選參數必須在前,默認參數在後

  2)當函數有多個參數時,把變化大的放在前面,變化小的參數放後面。變化小的參數就可以作為默認參數

   好處:降低調用函數的難度

  3)當有多個默認參數時,可以按順序賦值,也可使用參數名直接賦值

對於第3點:

def student(name, age, city=chongqing, gender=7):
    print(name:, name)
    print(age:, age)
    print(city:, city)
    print(gender:, gender)


student(frm, 7, chengdu, 6)    #依順序賦值
student(fzp, 7, gender=7)  #給gender參數賦值為7,這種情況下,city參數仍是默認的‘chongqing’

默認參數的一個典型問題,使用的時候需要註意:

def func(lis=[]):
    lis.append(1)
    print(lis)


func() #[1]
func() #[1, 1]

"這是因為解釋器執行函數定義時,默認參數值lis也被計算了,即[],因為默認參數lis也是一個變量,它指向對象[],每次調用該函數,如果改變了lis的內容,則下次調用時,默認參數的內容就變了,不再是函數定義時的[]了"引用廖大的解釋

對於該問題,我的理解是在執行append()方法時,只是往lis裏面添加了新的元素,並未改變其地址

lis = []
print(id(lis)) #2293538950856
lis.append(1)
print(id(lis)) #2293538950856

解決該問題,可以用None這個不變對象來實現:

def func(lis=None):
    if lis is None:
        lis = []
    lis.append(1)
    print(lis)


func() #[1]
func() #[1]

"為什麽要設計strNone這樣的不變對象呢?因為不變對象一旦創建,對象內部的數據就不能修改,這樣就減少了由於修改數據導致的錯誤。此外,由於對象不變,多任務環境下同時讀取對象不需要加鎖,同時讀一點問題都沒有。我們在編寫程序時,如果可以設計一個不變對象,那就盡量設計成不變對象"

  1、不可變對象:字符串(string)、(數值型number)、元組(tuple)、集合(set)
  2、可變對象:字典型(dictionary)、列表型(list)

3、可變參數

可變參數:傳入的參數個數可變

例:給定一組數字a,b,c……,請計算a2 + b2 + c2 + ……,要定義出這個函數,我們必須確定輸入的參數。由於參數個數不確定,我們首先想到可以把a,b,c……作為一個list或tuple傳進來,這樣,函數可以定義如下:

def result(numbers):
    sum = 0
    for n in numbers:
        sum += n * n
    return sum

在調用該方法的時候,需要先組裝出一個list或tuple

print(result([1, 2, 3]))  #14
print(result((1, 2, 3, 4)))  #30

如果用可變參數的話,就可以直接傳入參數,不需要先對參數進行組裝,可變參數用*標識

def result(*numbers):
    sum = 0
    for n in numbers:
        sum += n * n
    return sum


print(result(1, 2, 3, 4))  #30  直接給result函數傳值
tup = (1, 2, 3)
print(result(*tup)) #14  也可以傳入一個list或tuple,但需要在其前面加上*符號,否則會報錯:TypeError: can‘t multiply sequence by non-int of type ‘tuple‘ 

4、關鍵字參數

關鍵字參數:允許傳入任意個(包括0個)含參數名的的參數,這些參數在函數內部會自動組裝成一個dict,關鍵字參數用**標識

def student(name, age, **kwargs):
    print(name:, name, age:, age, other:, kwargs)

可見,student函數除了必選參數name和age外,還可接受關鍵字參數kwargs,在調用該函數的時候,可以只傳入必選參數

student(fzp, 24)

輸出結果為:

name: fzp age: 24 other: {}

從結果也可以看出,關鍵字參數在函數內部自動組裝成了一個dict,此處,關鍵字參數未傳值,所有是一個空字典{}

關鍵之參數傳值可采用 ‘key‘ = ‘value‘ 的形式

student(fzp, 24, address=chongqing, sex=man)

輸出結果為:

name: fzp age: 24 other: {address: chongqing, sex: man}

當然,關鍵字參數傳值可以直接傳入一個dict

dic = {address: chongqing, sex: man}
student(fzp, 24, **dic)

輸出結果為:

name: fzp age: 24 other: {address: chongqing, sex: man}

註意:

1、kwargs獲得的dict僅僅是dic的一個拷貝,對kwargs的改變不會影響函數外面的dic

2、直接傳入一個dict時,要在之前添加**,否則會將整個dict識別為一個位置參數,如下:

student(fzp, 24, dic)  
TypeError: student() takes 2 positional arguments but 3 were given

命名關鍵字參數

對於關鍵字參數,函數的調用者可以傳入任意不受限制的關鍵字參數。但是,又是我們或許想要限定關鍵字參數的名字,這時,就需要用到命名關鍵字參數

仍以student函數為例,如果只想接受address和sex為參數,可定義如下:

def student(name, age, *, address, sex):
    print(name:, name, age:, age, address:, address, sex:, sex)

和關鍵字參數**kwargs不同,命名關鍵字參數需要一個特殊分隔符**後面的參數被視為命名關鍵字參數

調用方式如下:

student(fzp, 23, address=chongqing, sex=man)

輸入結果:name: fzp age: 23 address: chongqing sex: man

註意:命名關鍵字參數必須給值,至於為什麽有了必傳的位置參數,還要有必傳的命名關鍵字參數,我覺得主要有兩點原因:

  1、命名關鍵字參數通過指定參數名稱的方式,可以明確當前參數的含義

  2、命名關鍵字參數不必像位置參數那樣按順序傳值,時傳值更加靈活

當然,命名關鍵字參數可以有缺省值,這樣,在調用的時候,就不必給其傳入值了:

def student(name, age, *, address, sex=man):
    print(name:, name, age:, age, address:, address, sex:, sex)

調用該函數:

student(fzp, 23, address=chongqing)

輸出結果為:name: fzp age: 23 address: chongqing sex: man

5、參數組合

在Python中定義函數,可以用必選參數、默認參數、可變參數、關鍵字參數和命名關鍵字參數,這5種參數都可以組合使用。但是請註意,參數定義的順序必須是:必選參數、默認參數、可變參數、命名關鍵字參數和關鍵字參數

舉例:

def func(a, b, c=3, *args, address, **kwargs):
    print(a:, a, b:, b, c:, c, args:, args, address:, address, kwargs:, kwargs)

調用該函數:

func(1, 2, 3, 4, 5, address=cq, d=char, e=dict)

輸入結果為:a: 1 b: 2 c: 3 args: (4, 5) address: cq kwargs: {‘d‘: ‘char‘, ‘e‘: ‘dict‘}

通過一個tuple和dict,也可以調用上述函數:

tup = (1, 2, 3, 4, 5)
kw = {address: cq, ax: sg}
func(*tup, **kw)

輸出結果為:

a: 1 b: 2 c: 3 args: (4, 5) address: cq kwargs: {ax: sg}

所以,對於任意函數,都可以通過類似func(*args, **kw)的形式調用它,無論它的參數是如何定義的

Python函數參數學習筆記