Python札记 -- 参数魔法
??? 在上一篇隨筆《Python凡人筆記 -- 裝飾器》中有園友提出我對Python中的參數(shù)魔法表述得不是很明確,故借此機會總結(jié)一下,再結(jié)合幾個例子,希望對大家有幫助。另外竹風(fēng)使用的是 Python 2.6.6
??? 參考資料:《Python基礎(chǔ)教程》(第2版)Magnus Lie Hetland
??? 一、Python的函數(shù)返回些什么?
??? 一般說的函數(shù),總會在計算之后返回點什么。像在 Pascal 里面,就有分函數(shù)和過程。讓我們一起從例子里面看看 Python 的函數(shù)到底會返回些什么。
??? 這里的return語句只起到結(jié)束函數(shù)的作用:
1 >>> x = test() 2 This is printed 3 4 >>> x 5 >>> 6 7 >>> print x 8 None??? 可以看到,第二個print語句被跳過了。單單看 x 好像沒有任何東西,通過 “print x” 我們可以看到一個熟悉的值:None。
??? 這么看來,在Python里面,所有的函數(shù)都會返回值;當(dāng)不需要它們返回值的時候,它們就返回None。
??? 二、什么類型的參數(shù)可以修改?
??? 函數(shù)通過參數(shù)來獲得一系列的值。在Python中,字符串(以及數(shù)字和元組)是不可變的,即無法被修改(也就是說只能用新的值覆蓋),用學(xué)術(shù)點的話來說:在函數(shù)內(nèi)為不可變類型的參數(shù)賦予新值不會改變外部任何變量的值。???
??? 我們可以看到,name 雖然作為參數(shù)傳遞到函數(shù)中,但是最后 name 的值并沒有任何改變。其實上面的代碼工作方式類似于下面這樣:
1 >>>name = "Mrs Entity" 2 >>>n = name #相當(dāng)于傳參數(shù) 3 >>>n = "Mr Gumby" #在函數(shù)內(nèi)部給n一個新的字符串 4 >>>name 5 'Mrs Entity'??? 那么如果我們傳的參數(shù)是一個可變的數(shù)據(jù)結(jié)構(gòu)呢,比如列表?估計大家已經(jīng)能猜到結(jié)果了。
1 >>> def change(n): 2 ... n[0] = "Mr Gumby" 3 ... 4 >>> name = ["Mrs Entity", "Mrs Thing"] 5 >>> change(name) 6 >>> name 7 ['Mr Gumby', 'Mrs Thing']??? 這里發(fā)現(xiàn)參數(shù)的值改變了,這也是與前面的例子中最重要的區(qū)別。要弄清楚的是,當(dāng)兩個變量同時引用一個列表的時候,它們的確是同時引用了一個列表。如果想避免出現(xiàn)這種情況,可以復(fù)制一個列表的副本。具體做法就是傳遞參數(shù)的時候,將列表的分片作為參數(shù),比如:change(name[:])。這樣的話,原始的列表就是安全的。
??? PS:竹風(fēng)剛?cè)腴T的時候曾經(jīng)犯過將原始列表傳入函數(shù)的錯誤,關(guān)鍵是函數(shù)里面有一個 remove 操作,結(jié)果大家也能猜到了。。。
??? 那如果要對一個不可變的參數(shù)進行操作呢?比如一個數(shù)字,這又該怎么辦?
??? 這個時候我們應(yīng)該從函數(shù)中返回所有需要的值,如果值多于一個拿就用元組的形式返回。例如,將變量的數(shù)值增加1的函數(shù)可以這么寫:
??? 如果真的想改變參數(shù)的話,我們可以使用一點小技巧,將值放在列表中(還記得列表是可修改的么?):
1 >>> def inc(x): x[0] = x[0] + 1 2 ... 3 >>> foo = [10] 4 >>> inc(foo) 5 >>> foo 6 [11]??? 使用哪種方式,全憑個人喜好~~
??? 三、位置參數(shù),關(guān)鍵字參數(shù),默認參數(shù)
??? 到目前為止,前面例子中使用的都是位置參數(shù),因為它們的位置很重要——事實上比它們的名字更重要。先看些簡單的列子,來看看為什么會引入關(guān)鍵字參數(shù)。
??? 這兩個函數(shù)所實現(xiàn)的功能是完全一樣的,唯一的區(qū)別就是參數(shù)的順序。當(dāng)參數(shù)很多的時候,竹風(fēng)覺得參數(shù)的順序是很難記住的。為了讓事情簡單些,我們可以提供參數(shù)的名字。
1 >>> hello_1(greeting = "Hello", name = "World") 2 Hello, World! 3 >>> hello_1(name = "World", greeting = "Hello") 4 Hello, World! 5 >>> hello_2(greeting = "Hello", name = "World") 6 World, Hello!??? 提供了參數(shù)的名字后,順序就無關(guān)緊要的,就好像上面的 hello_1 調(diào)用。唯一要注意的,就是參數(shù)名和值一定要對應(yīng),不然就會出現(xiàn) hello_2 那樣輸出 “World Hello!”了。
??? 這類使用參數(shù)名提供的參數(shù)叫做關(guān)鍵字參數(shù)。主要作用在于可以明確每個參數(shù)的作用,也就避免了下面這樣奇怪的調(diào)用:
??? 竹風(fēng)以為,大部分園友看見第一種調(diào)用的時候估計是虎軀一震的。。。第二種調(diào)用雖然打的字多了點,但是參數(shù)的含義變得更加清晰,而且就算弄亂了參數(shù)的順序,對于程序的功能也沒有任何影響。
??? 關(guān)鍵字參數(shù)最實用的地方在于可以在函數(shù)中給參數(shù)提供默認值,嘎嘎,再也不用擔(dān)心調(diào)用函數(shù)的時候漏參數(shù)了~~???
??? 最后關(guān)于位置參數(shù)和關(guān)鍵字參數(shù)需要注意的是:同時使用位置和關(guān)鍵字參數(shù)的時候,必須把位置參數(shù)放置在關(guān)鍵字參數(shù)的前面,否則,解釋器就不知道這些參數(shù)到底應(yīng)該處在什么位置了。
??? 四、收集參數(shù)與解開參數(shù)
??? 鋪墊了這么久,終于來到今天的兩大Boss面前了。位置參數(shù)拉好仇恨,關(guān)鍵字參數(shù)做好治療,其他人全力輸出吧!(博主wow五人本打多了。。。無視就好。。。)
??? 先說說收集參數(shù),在定義函數(shù)時,*params 收集其余的位置參數(shù)(parameter),返回元組;**kwparams 收集其余的關(guān)鍵字參數(shù)(key word parameter),返回字典。
??? 有時候能提供任意數(shù)量的參數(shù)是相當(dāng)方便的,比如一個函數(shù) add 可以求任意個數(shù)字的和,add(1,2,3) 和 add(1,2,3,4,5) 都能給出正確結(jié)果。
??? 用戶可以給函數(shù)提供任意多的參數(shù),實現(xiàn)起來也不難。注意例子中雖然只提供了一個參數(shù),但是前面加上了個星號。???
??? 可以看到,結(jié)果作為元組打印出來。參數(shù)前的星號將所有傳進來的參數(shù)放置在同一個元組中。也可以說是把這些值收集起來,然后使用。當(dāng)然也可以聯(lián)合普通參數(shù)來使用:
1 >>> def print_params_2(title, *params): 2 ... print "title =",title 3 ... print params 4 ... 5 >>> print_params_2("Test2", 1, 2, 3) 6 title = Test2 7 (1, 2, 3) 8 >>> print_params_2("Test3") 9 title = Test3 10 ()??? 完全沒問題!所以星號的意思就是“收集其余的位置參數(shù)”。如果不提供任何收集的元素,params就是個空元組。
??? 讓我們看下關(guān)鍵字參數(shù)的“收集”操作。
??? 返回的是字典而不是元組。將它們放在一起看看:
>>> def print_params_4(x, y, z=3, *pospar, **keypar): ... print x, y, z ... print pospar ... print keypar ... >>> print_params_4(1, 2, 3, 5, 6, 7, foo='A', bar='B') 1 2 3 (5, 6, 7) {'foo': 'A', 'bar': 'B'} >>> print_params_4(1, 2, 3) 1 2 3 () {}??? ok,跟我們期望的結(jié)果沒有差別。
??? 收集參數(shù)打完了,再來打展開參數(shù)。
??? 展開參數(shù),在調(diào)用函數(shù)時,*params 將元組拆分為位置參數(shù)(parameter)傳入;**kwparams 將字典拆分為關(guān)鍵字參數(shù)(key word parameter)傳入。
??? 這是兩個典型的例子:???
???? 最后我們看看這幾種方式一起使用的情況:
1 >>> def finally_test(x, y, z=3, *params, **kwparams): #參數(shù)的順序應(yīng)該為:位置參數(shù),關(guān)鍵字參數(shù),*params,**kwparams 2 ... print "pos x =",x 3 ... print "pos y =",y 4 ... print "key z =",z 5 ... print "params =",params 6 ... print "kwparams =",kwparams 7 ... 8 >>> list = [1,2,3,4,5] 9 >>> dict = {"foo":"A", "bar":"B"} 10 11 >>> finally_test(1,2,*list,**dict) #沒有指定z的值,所以將list[0]作為z的值,其他收集為params 12 pos x = 1 13 pos y = 2 14 key z = 1 15 params = (2, 3, 4, 5) 16 kwparams = {'foo': 'A', 'bar': 'B'} 17 18 >>> finally_test(1,2,3,list,dict) #錯誤的調(diào)用方法,會將dict也認為是個位置參數(shù) 19 pos x = 1 20 pos y = 2 21 key z = 3 22 params = ([1, 2, 3, 4, 5], {'foo': 'A', 'bar': 'B'}) 23 kwparams = {} 24 25 >>> finally_test(1,2) #沒有多余的位置參數(shù)和關(guān)鍵字參數(shù)的情況 26 pos x = 1 27 pos y = 2 28 key z = 3 29 params = () 30 kwparams = {} 31 32 >>> finally_test(1,2,3,*list,**dict) #正確的調(diào)用方式 33 pos x = 1 34 pos y = 2 35 key z = 3 36 params = (1, 2, 3, 4, 5) 37 kwparams = {'foo': 'A', 'bar': 'B'}??? 其實一般情況下會這么定義函數(shù):
??? def foo(*params,**kwparams):
??????? pass
??? 到這里就總結(jié)完了,希望對大家有用。如有不足,歡迎大家指正交流,謝謝^_^
轉(zhuǎn)載于:https://www.cnblogs.com/PandaBamboo/archive/2013/02/05/2892731.html
總結(jié)
以上是生活随笔為你收集整理的Python札记 -- 参数魔法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图片搜索
- 下一篇: ios 关于MBProgressHUD简