Python - 函數的參數


題外話:由於時間關係,沒能保持必定的更新頻率。但仍是會一直堅持的~數組

以前介紹了Python函數的定義,今天分享一下Python函數的參數吧!內容會有點多~app

Python的函數定義比較簡單,藉助於關鍵字def進行實現,可是參數的靈活度卻很是大。除了正常定義的必選參數外,還可使用默認參數、可變參數、關鍵字參數、命名關鍵字參數以及參數組合,這使得函數定義出來的接口,不只能處理複雜的參數,還能簡化調用者的代碼。函數


1、位置參數

  • 在函數定義的時候,指定參數的位置順序。位置參數必須在被調用函數定義中的準確順序來進行傳遞。

例如:計算x的n次方ui

def powern(x,n):
    s = 1
    while n >0:
        s = s * x
        n = n -1
    return s

x與n這兩個參數都是位置參數。調用函數時,必須傳入且傳入的兩個值按照位置順序依次賦給參數x和n,若缺省,則會報錯。例如:code

>>> powern(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: powern() missing 1 required positional argument: 'n'

2、默認參數

  • 在函數定義中,爲參數預先定義默認值。當在函數調用時,若沒有爲參數提供指定值,則使用默認值。
    例如:仍舊是求x的n次方,可是默認爲x的3次方。
def powern( x,n = 3):
    s = 1
    while n >0:
        s = s * x
        n = n -1
    return s

執行:powern(2),至關於調用powern(2,3)
若是要求2的四次方,則須要執行:powern(2,4)對象

設置默認參數的好處?
默認參數能夠簡化函數的調用,下降調用函數的難度。不管是簡單調用仍是複雜調用,函數只需定義一個。
例如上述powern()的例子,當傳入n的其餘值時,則能夠實現x的其餘n次方。接口

可是在使用默認參數的時候,若是使用不當,也會有坑。先來了解一下可變參數和不可變參數做爲函數參數時的不一樣:ip

  • 不可變參數做爲函數參數
>>> a = 1
>>> def func(a):
...     print('func_id:',id(a))
...     a = 2
...     print('after_func_id:',id(a),'id(2):',id(2))
...
>>> print('out_of_func_id:',id(a),'id(1):',id(1))
out_of_func_id: 501962480  id(1): 501962480   # 全局變量a的id
>>> func(a)            # 將全局參數a傳入函數
func_id: 501962480    # a=1 的id
after_func_id: 501962496  id(2): 501962496  
>>> print(a)            # 退出函數,a的值仍爲1
1

當把全局a傳遞給函數後,函數自動複製一份引用。執行完a=2以後,id(a)的內存地址發生變化。可是跟外層的a沒有關係。內存

  • 可變對象做爲函數參數
>>> a = []
>>> def func2(a):
...     print('func2_id:',id(a))
...     a.append(1)
...
>>> print('out_of_func2_id',id(a))
out_of_func2_id 59694296
>>> func2(a)
func2_id: 59694296
>>> print(a)
[1]

變量a的類型爲list,是可變對象。函數的引用指向的是可變對象,地址沒有發生變化,因此函數操做後,a的內容發生了改變。
因此當再次操做func2(a)函數時,產生跟預期不同的結果:ci

>>> func2(a)
func2_id: 59694296    # a地址不變
>>> print(a)
[1, 1]        # 由於第一次執行func2(a)時,已經修改了a=[1],再次調用時,在[1]裏新增
  • 使用可變對象做爲默認參數
    例如:
def add_end( L=[] ):  # 設置爲一個list變量L(對象可變)
    L.append('end')
    return L
>>> add_end( )
['end']
>>> add_end()  
['end', 'end']

當連續重複使用默認參數調用時,結果出現錯誤。
Python函數在定義的時候,默認參數L的值就被計算出來了,即[]。L也是一個變量,它指向對象[],每次調用該函數,若是改變了L的內容,則下次調用時,默認參數的內容就變了,再也不是函數定義時的[]了。
能夠改成:

def add_end( L=None ):  # L爲不變對象  
    if L is None:          
    L = []            
    L.append('end')   
    return L

則不管調用多少次,都不會出現問題。
因此,定義默認參數要牢記一點:默認參數必須指向不變對象!由於不變對象一旦建立,對象內部的數據就不能修改,這樣就減小了因爲修改數據致使的錯誤。此外,因爲對象不變,多任務環境下同時讀取對象不須要加鎖。

  • 設置默認參數時,有幾點須要注意
    一.必選參數在前,默認參數在後,不然Python的解釋器會報錯。
    二.如何設置默認參數?當函數有多個參數時,把變化大的參數放前面,變化小的參數放後面。變化小的參數就能夠做爲默認參數。
    三.不要使用可變對象做爲默認參數。

3、可變參數*args

可變參數,即傳入的參數個數是可變的,0至任意個。
由於參數個數不肯定,則可使用一個list 或者tuple傳進來。以後在函數調用時會自動組裝爲一個tuple。
例如:

def calc(numbers):  # 變量        
    sum = 0               
    for n in numbers:       
        sum = sum + n * n   
    return sum            
>>> calc( [1,2,3] )   # 傳入的是一個list
14

利用可變參數 *args:

def calc( *numbers ):  
    sum = 0        
    for n in numbers:    # 在函數內部,numbers組裝成一個tuple
    sum = sum + n * n
    return sum
>>> calc( )            # 0個參數  
0
>>> calc( 1,3,5,7 )    # 多個參數 
84
>>> num = [1,2,3]      # list
>>> calc( *num )       # *list –> tuple
14   
>>> t = (1,3,5)
>>> calc( t )          # tuple(錯誤)  
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in calc
TypeError: can't multiply sequence by non-int of type 'tuple'
>>> calc( *t )                  
35

函數代碼徹底不變。可是,調用該函數時,能夠傳入任意個參數,包括0個參數。

4、關鍵字參數**kw

關鍵字參數**kw容許傳入0個至任意個含參數名的參數,這些關鍵字參數在函數內部自動組裝爲一個dict。例如:

def person(name , age , **kw ):
    print('name:',name,'age:',age,'other:',kw)
>>> person('xiong',18)
name: xiong age: 18 other: {}
>>> person('xiong',18,city = 'SH')          # city是本來沒有的參數,可是由於有**kw
name: xiong age: 18 other: {'city': 'SH'}

關鍵參數有什麼用?能夠擴展函數的功能。好比在person()函數裏面,能夠保證接收到name和age這兩個參數。可是若是提供更多參數,也能收到。固然也能夠先組裝一個dict,再把該dict轉換爲關鍵字參數傳遞進去:

>>> extra ={'city':'shanghai','job':'SET'}                     # dict的定義
>>> person('xiong',18,city = extra['city'],job=extra['job'])   # dict的使用
name: xiong age: 18 other: {'city': 'shanghai', 'job': 'SET'}  # dict的內容
>>> person('xiong',18,**extra)
name: xiong age: 18 other: {'city': 'shanghai', 'job': 'SET'}

【總結】**extra表示把extra這個dict的全部key-value用關鍵字參數傳入到函數的**kw參數,kw將得到一個dict,注意kw得到的dict是extra的一份拷貝,對kw的改動不會影響到函數外的extra。

5、命名關鍵字參數

若是要限制關鍵字參數的名字,就能夠用命名關鍵字參數。須要一個特殊分隔符「」,「」後面的參數被視爲命名關鍵字參數。若是缺乏「*」,Python解釋器則沒法識別位置參數和命名關鍵字參數。在調用時,必須指定參數名字與參數值。
例如,只接收city和job做爲關鍵字參數,可使用以下定義:

def person( name ,age,*,city,job):
    print(name , age , city , job )
>>> person('xiong', 18, city='shanghai', job='tester')
xiong 18 shanghai tester

若是函數定義中已經有了一個可變參數,後面跟着的命名關鍵字參數就再也不須要一個特殊分隔符*了:

>>> def person( name,age,*args,city,job ):     # 此處city和job也是命名關鍵字參數
...   print(name, age, city, job)

命名關鍵字參數必須傳入參數名,若是沒有傳入參數名,調用將會報錯:

>>> person('xlp',18,'shanghai','tester')          # 錯誤調用 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: person() missing 2 required keyword-only arguments: 'city' and 'job'
>>> person('xlp',18,city='shanghai',job='tester')  # 正確調用 
xlp 18 shanghai tester

命名關鍵字參數能夠有缺省值,從而簡化調用:

>>> def person1(name,age,*,city='shanghai',job):
...   print(name,age,city,job)
...
>>> person1('xlp',18,job='engineer')
xlp 18 shanghai engineer

6、參數組合

在Python中定義函數,能夠用位置參數、默認參數、可變參數、關鍵字參數和命名關鍵字參數,這5種參數均可以組合使用。
可是要注意,參數定義的順序必須是:位置參數、默認參數、可變參數、命名關鍵字參數和關鍵字參數。

【總結】

(1)定義可變參數和關鍵字參數的語法:
*args是可變參數,args接收的是一個list、tuple;
**kw是關鍵字參數,kw接收的是一個dict;
(2)調用函數時如何傳入可變參數和關鍵字參數的語法:
可變參數直接傳入:func(1,2,3)
可變參數間接傳入:先組裝成list或tuple,l=(1,2,3),再經過args傳入,func(l)
關鍵字參數直接傳入:func(a=1,b=2)
關鍵字參數間接傳入:先組裝成dict,d={‘a’:1,’b’:2},再經過kw傳入,func(d)
(3)命名關鍵字參數 是爲了限制調用者能夠傳入的參數名,同時能夠提供默認值。
(4)定義命名的關鍵字參數在沒有可變參數的狀況下,不要忘記寫分隔符*,不然定義的將是位置參數。


❤ thanks for watching, keep on updating...

相關文章
相關標籤/搜索