Python函數參數學習筆記
在學習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]
"為什麽要設計str
、None
這樣的不變對象呢?因為不變對象一旦創建,對象內部的數據就不能修改,這樣就減少了由於修改數據導致的錯誤。此外,由於對象不變,多任務環境下同時讀取對象不需要加鎖,同時讀一點問題都沒有。我們在編寫程序時,如果可以設計一個不變對象,那就盡量設計成不變對象"
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函數參數學習筆記