導(dǎo)語
??由于之前遇到過幾次有關(guān)于參數(shù)類型的坑,以及經(jīng)常容易把一些參數(shù)類型搞混淆,現(xiàn)在做一下有關(guān)參數(shù)類型的總結(jié)記錄以及對之前踩坑經(jīng)歷的分析。
參數(shù)類型
首先我們列舉一下有關(guān)于Python的參數(shù)類型,以及實際上的運用和原理。
- 位置參數(shù)(必選參數(shù))
- 默認參數(shù)
- 可變參數(shù)
- 關(guān)鍵字參數(shù)
位置參數(shù)(必選參數(shù))
首先是位置參數(shù),同時也被稱作 必選參數(shù) ,位置參數(shù)很好理解,只要記住這點:
- 在函數(shù)定義時直接給定的 此參數(shù)名稱 ,調(diào)用時按照 參數(shù)的位置順序 ,依次賦予參數(shù)值。
示例:
def person_info(name, age):
print("My name is %s, I am %s years old" % (name, age))
person_info("zhangsan", "49")
# name,age都是位置參數(shù),按照位置順序,函數(shù)中依次接收參數(shù)值。
默認參數(shù)
默認參數(shù),默認參數(shù)存在許多便利的地方,但是同時也存在許多坑,等到后面我們再去仔細分析下為什么存在這些坑,以下幾點我們需要注意的:
- 可以為一個或者多個參數(shù) 指定默認值 ,當調(diào)用函數(shù)時可以不用傳入該參數(shù)值,大大降低函數(shù)調(diào)用的難度。
- 當需要用傳入的參數(shù)值代替默認參數(shù)的默認值時,可以按照參數(shù)位置順序傳入,同時也可以指定參數(shù)名傳入。
示例:
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')
可變參數(shù)
可變參數(shù),顧名思義就是傳入的 參數(shù)數(shù)量 是可變的:
- 可變參數(shù)在實際中,傳入的數(shù)量可以是任意多個,但也可以沒有。
- 而可變參數(shù)會在傳入函數(shù)內(nèi)部時,是一個 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)
# 當傳入的參數(shù)為list時,會將list中所有的元素作為可變參數(shù),傳進去
關(guān)鍵字參數(shù)
當 可變參數(shù) 在 傳入0個或者任意個參數(shù) 時,這些可變參數(shù)會在函數(shù)調(diào)用時自動組裝成一個 tuple 。而 關(guān)鍵字參數(shù) 也允許你傳入 0個或者任意個含參數(shù)名的參數(shù) ,這些關(guān)鍵字參數(shù)會函數(shù)內(nèi)部自動組裝為一個 dict 。調(diào)用函數(shù)時,可以只傳入必選參數(shù)。
- 擴展函數(shù)的功能,**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)
命名關(guān)鍵字參數(shù)
對于關(guān)鍵字參數(shù),函數(shù)的調(diào)用者可以傳入 任意不受限制的關(guān)鍵字參數(shù) 。但是針對到底傳入了哪些參數(shù),就需要通過函數(shù)內(nèi)部分析檢查。所以命名關(guān)鍵字參數(shù)就是限制傳入的參數(shù)的名字,只能傳我已命名關(guān)鍵字參數(shù)。
- 命名關(guān)鍵字參數(shù)需要一個特殊分隔符*,分隔符后面的參數(shù)會被視為命名關(guān)鍵字參數(shù)。
- 當函數(shù)中已經(jīng)存在一個 可變參數(shù) ,后面跟著的命名關(guān)鍵字參數(shù)就不需要一個* 特殊分隔符——“ ”**。
- 命名關(guān)鍵參數(shù)可以有默認值,從而簡化調(diào)用。
- 命名關(guān)鍵參數(shù)必須傳入一個參數(shù)名,這和位置參數(shù)不同。如果沒有傳入?yún)?shù)名,調(diào)用將會報錯。
示例:
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')
參數(shù)組合調(diào)用規(guī)則
在python定義函數(shù)過程中,可以用位置參數(shù)、默認參數(shù)、可變參數(shù)、關(guān)鍵字參數(shù)、命名關(guān)鍵字參數(shù)。這五種參數(shù)都可以通過組合使用。需要注意的是:
- 這五種參數(shù)定義的順序必須是:位置參數(shù)、默認參數(shù)、可變參數(shù)、命名關(guān)鍵字參數(shù)、關(guān)鍵字參數(shù)。
位置參數(shù)和默認參數(shù)組合
def Person(name, age=20):
print(name,age)
Person('zhangsan')
Person('zhangsan', 20)
位置參數(shù)、默認參數(shù)、可變參數(shù)組合
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')
位置參數(shù)、默認參數(shù)、可變參數(shù)、命名關(guān)鍵字參數(shù)組合
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')
關(guān)于參數(shù)定義的一些坑
默認參數(shù)陷阱
關(guān)于默認參數(shù)陷阱的問題,我們先來看一看一個示例:
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")
這個輸出的結(jié)果應(yīng)該是意料之中,現(xiàn)在我們這時候再調(diào)用Book()方法,看看會發(fā)生什么:
??這時候輸出結(jié)果,竟然把之前的First one都輸出,看了他們的id,發(fā)現(xiàn)都是同一塊內(nèi)存地址,這時候就開始納悶了,那么來找找出現(xiàn)這種狀況的原因。
經(jīng)過查閱官方資料發(fā)現(xiàn),這是一段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對默認值只計算一次,對于可變對象,在后續(xù)調(diào)用的情況下會累積傳遞給他們 。而list、dict等這種都屬于可變對象。
??那么對于這種默認值陷阱,我們是該如何避免造成一些不必要的麻煩呢?大致有兩種解決方法:
- 避免使用可變對象作為默認值。
- 在參數(shù)定義的時候可以使用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')
慎用變長參數(shù)
?? 前面已經(jīng)介紹過了,Python是支持可變長度的參數(shù)列表,可以在函數(shù)定義參數(shù)時使用*args和**kwargs兩個特殊的語法來實現(xiàn)。
那為什么要說慎用變長參數(shù),我總結(jié)了一下有以下幾個原因:
- 使用過于靈活。比如在我上面有關(guān)不同類型參數(shù)組合使用的示例中,在位置參數(shù)和默認參數(shù)在的情況下,還有可變參數(shù)、關(guān)鍵字參數(shù)、命名關(guān)鍵字參數(shù)。這就很容易是的這個函數(shù)的 簽名不夠清晰 ,調(diào)用者需要花費時間去了解你這個方法該如何調(diào)用。所以這就很容易使得團隊開發(fā)中效率低效。
- 另外一個原因,如果一個函數(shù)的列表過于長,雖然可以通過使用*args, **kwargs來簡化函數(shù),但同時也意味這個函數(shù)或許有更好的實現(xiàn)方式,有重構(gòu)的必要。
說完了要慎用,在說說看我們常用的變長參數(shù)的使用場景:
- 為函數(shù)添加一個裝飾器。
- 如果參數(shù)的數(shù)目不確定的時候,可以考慮使用變長參數(shù)。比如讀取一些配置文件中的配置項時。
- 用來實現(xiàn)函數(shù)的多態(tài),或者在繼承情況下子類需要調(diào)用父類的某些方法。
總結(jié)
?? 關(guān)于的Python參數(shù)類型就寫到這里了,剛開始學(xué)Python的時候,經(jīng)常被函數(shù)定義的參數(shù)類型搞懵,后面看了一些教程,自己在寫一些腳本的時候遇到的一些坑,并且在看一些大牛分析背后的原理,后面感覺收獲良多。后面干脆想把自己學(xué)習(xí)過程遇到的東西都整理一下,做個記錄,加深理解。
下面是我參考的一些博客文章:
https://www.liaoxuefeng.com/wiki/1016959663602400/1017261630425888
http://cenalulu.github.io/python/default-mutable-arguments/
https://www.cnblogs.com/Clonglegs/p/9564873.html
https://blog.csdn.net/u014745194/article/details/70158926
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
