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