Python 參數類型以及常見的坑

這是我參與8月更文挑戰的第4天,活動詳情查看:8月更文挑戰html

導語

因爲以前遇到過幾回有關於參數類型的坑,以及常常容易把一些參數類型搞混淆,如今作一下有關參數類型的總結記錄以及對以前踩坑經歷的分析。python

參數類型

首先咱們列舉一下有關於Python的參數類型,以及實際上的運用和原理:git

  • 位置參數(必選參數)
  • 默認參數
  • 可變參數
  • 關鍵字參數

位置參數(必選參數)

首先是位置參數,同時也被稱做必選參數,位置參數很好理解,只要記住這點:github

  • 在函數定義時直接給定的此參數名稱,調用時按照參數的位置順序,依次賦予參數值

示例:數組

def person_info(name, age):
    print("My name is %s, I am %s years old" % (name, age))
    
person_info("zhangsan", "49")    
複製代碼

(name,age都是位置參數,按照位置順序,函數中依次接收參數值。)bash

默認參數

默認參數,默認參數存在許多便利的地方,可是同時也存在許多坑,等到後面咱們再去仔細分析下爲何存在這些坑,如下幾點咱們須要注意的:markdown

  • 能夠爲一個或者多個參數指定默認值,當調用函數時能夠不用傳入該參數值,大大下降函數調用的難度。
  • 當須要用傳入的參數值代替默認參數的默認值時,能夠按照參數位置順序傳入,同時也能夠指定參數名傳入。

示例:app

def person_info(name, age, sex='man'):
    print("My name is %s, I am %s years old, I am %s" % (name, age, sex))

person_info('zhangsan', '15')
person_info('lisi', '15', 'women')
person_info('lisi', '20', sex='women')
複製代碼

可變參數

可變參數,顧名思義就是傳入的參數數量是可變的:ide

  • 可變參數在實際中,傳入的數量能夠是任意多個,但也能夠沒有;
  • 而可變參數會在傳入函數內部時,是一個tuple的形式;

示例:函數

def add(*numbers):
    sum = 0
    for i in numbers:
        sum+=i
    return sum

print(add(1,3,4,2,1,4,1,3)) 

numbers=[2,3,4,1,5]
add(*numbers)
複製代碼

(當傳入的參數爲list時,會將list中全部的元素做爲可變參數,傳進去)

關鍵字參數

  • 關鍵字參數也容許你傳入0個或者任意個含參數名的參數,這些關鍵字參數會函數內部自動組裝爲一個dict。
  • 調用函數時,能夠只傳入必選參數。(擴展函數的功能,**kwargs)

示例:

def person_info(**kw):
    for key,value in kw.items():
        print(key, value)

person_info(name='zhangsan', age=15)
person = {'name': 'zhangsan', 'age': 13}
person_info(**person)
複製代碼

命名關鍵字參數

對於關鍵字參數,函數的調用者能夠傳入任意不受限制的關鍵字參數。可是針對到底傳入了哪些參數,就須要經過函數內部分析檢查。因此命名關鍵字參數就是限制傳入的參數的名字,只能傳我已命名關鍵字參數。

  • 命名關鍵字參數須要一個特殊分隔符*,分隔符後面的參數會被視爲命名關鍵字參數。
  • 當函數中已經存在一個可變參數,後面跟着的命名關鍵字參數就不須要一個特殊分隔符*。
  • 命名關鍵參數能夠有默認值,從而簡化調用。
  • 命名關鍵參數必須傳入一個參數名,這和位置參數不一樣。若是沒有傳入參數名,調用將會報錯。

示例:

def person_info(name, *, age, sex):
    print(name, age, sex)

def person_info2(name, *args, age, sex):
    for i in args:
        print(i)
    print(name, age, sex)
    
person_info('zhangsan', age=12, sex='man')
person_info2('zhangsan', 'sksks', 'ssk', age=13, sex='man')                    
複製代碼

參數組合調用規則

在python定義函數過程當中,能夠用位置參數、默認參數、可變參數、關鍵字參數、命名關鍵字參數。這五種參數均可以經過組合使用。須要注意的是:

  • 這五種參數定義的順序必須是:位置參數、默認參數、可變參數、命名關鍵字參數、關鍵字參數。

位置參數和默認參數組合

def Person(name, age=20):
    print(name,age)

Person('zhangsan')
Person('zhangsan', 20)        
複製代碼

位置參數、默認參數、可變參數組合

def Person(name, age=20, *args):
    for i in args:
        print(i)
    print(name, age)

Person('zhangsan')
Person('zhangsan', 22, "Beijing")
Person('zhangsan', age=22, 'Shanghai')    
複製代碼

位置參數、默認參數、可變參數、命名關鍵字參數組合

def Person(name, age=20, *args, city, **kwargs):
    for i in args:
        print(i)
    for key,value in kwargs.items():
        print(key, value)
    print(name, age, city)

Person('zhangsan', age=12, 'Author', city='Shanghai', company='Shanghai Software')        
複製代碼

關於參數定義的一些坑

默認參數陷阱

關於默認參數陷阱的問題,咱們先來看一看一個示例:

def Book(book, book_list=[]):
    print(id(book_list))
    book_list.append(book)
    for book in book_list:
        print(book)
    print(id(book_list))    

test = Book("First One")                
複製代碼

輸出的結果:

140699715685128
First One
140699715685128
複製代碼

這個輸出的結果應該是意料之中,如今咱們這時候再調用Book()方法,看看會發生什麼:

>>> test = Book("First One")
140699715685128
First One
140699715685128
>>> test2 = Book("Second One")
140699715685128
First One
Second One
140699715685128
複製代碼

這時候輸出結果,居然把以前的First one都輸出,看了他們的id,發現都是同一塊內存地址,這時候就開始納悶了,那麼來找找出現這種情況的緣由。 通過查閱官方資料發現,這是一段Python官方文檔給出的解釋:

Important warning: The default value is evaluated only once. This makes a difference when the default is a mutable object such as a list, dictionary, or instances of most classes. For example, the following function accumulates the arguments passed to it on subsequent calls:

咱們來看看解釋分析下,Python官方文檔給出的理由就是Python對默認值只計算一次,對於可變對象,在後續調用的狀況下會累積傳遞給他們。而list、dict等這種都屬於可變對象。

那麼對於中默認值陷阱,咱們是該如何避免形成一些沒必要要的麻煩呢?大體有兩種解決方法:

  • 避免使用可變對象做爲默認值
  • 在參數定義的時候可使用None對象做爲佔位符。

第二種解決方法:

def Book(book, book_list=None):
    print(book_list)
    if book_list is None:
        book_list = []
    book_list.append(book)
    for book in book_list:
        print(book)
    print(id(book_list))  
    
test1 = Book('First one')
test2 = Book('Second one')    
複製代碼

測試結果:

>>> test1 = Book('First one')
None
First one
140057693903624
>>> test2 = Book('Second one') 
None
Second one
140057693903624
複製代碼

慎用變長參數

前面已經介紹過了,Python是支持可變長度的參數列表,能夠在函數定義參數時使用*args和**kwargs兩個特殊的語法來實現。 那爲何要說慎用變長參數,我總結了一下有如下幾個緣由:

  • 使用過於靈活。好比在我上面有關不一樣類型參數組合使用的示例中,在位置參數和默認參數在的狀況下,還有可變參數、關鍵字參數、命名關鍵字參數。這就很容易是的這個函數的簽名不夠清晰,調用者須要花費時間去了解你這個方法該如何調用。因此這就很容易使得團隊開發中效率低效。
  • 另一個緣由,若是一個函數的列表過於長,雖然能夠經過使用*args, **kwargs來簡化函數,但同時也意味這個函數或許有更好的實現方式,有重構的必要。

說完了要慎用,在說說看咱們經常使用的變長參數的使用場景:

  • 爲函數添加一個裝飾器。
  • 若是參數的數目不肯定的時候,能夠考慮使用變長參數。好比讀取一些配置文件中的配置項時。
  • 用來實現函數的多態,或者在繼承狀況下子類須要調用父類的某些方法。

總結

關於的Python參數類型就寫到這裏了,剛開始學Python的時候,常常被函數定義的參數類型搞懵,後面看了一些教程,本身在寫一些腳本的時候遇到的一些坑,而且在看一些大牛分析背後的原理,後面感受收穫良多。後面乾脆想把本身學習過程遇到的東西都整理一下,作個記錄,加深理解。

下面是我參考的一些博客文章:

www.liaoxuefeng.com/wiki/101695… cenalulu.github.io/python/defa… www.cnblogs.com/Clonglegs/p… blog.csdn.net/u014745194/…

相關文章
相關標籤/搜索