這裏咱們看看Python中函數定義的語法,函數的局部變量,函數的參數,Python中函數的形參能夠有默認值,參數的傳遞是賦值操做,在函數調用時,能夠對實參進行打包和解包html
1,函數定義python
關鍵字def引出函數定義,後面跟着函數名以及用括號括起來的一系列參數,而後從下一行開始函數體(function body),而且要縮進。app
生成一個Fibnacci數列的序列,最大不超過某個數的函數函數
1 def fib(n): 2 '''get a list of fibnacci series to n''' 3 a, b = 0, 1 4 result = [] 5 while a<n: 6 result.append(a) 7 a, b = b, a+b 8 return result
運行:spa
>>> fib(3000)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584]code
2,函數的局部變量htm
[這裏的符號表(symbol table)等同於命名空間(namespace)]對象
函數體的執行會爲這個函數的局部變量引入一個新的符號表(symbol table)。全部函數體中的賦值語句(assignment statement),都會把變量名和值存在這個符號表中。blog
而函數體中的引用一個變量時,首先查看函數的符號表,若是這個函數定義包裹在其它函數定義中,就依次查看外圍函數的符號表,而後查看全局符號表(也就是函數所屬的module的符號表),最後查看Python的內置類型和變量的符號表。ip
函數的行參也是存在於函數的局部符號表中。
一個例子,函數中引用的是在局部符號表中的參數l,而不是全局符號表中的l。
1 l = ['a', 'b'] #輸出[1,2] 2 def f(l): 3 print l 4 if __name__ == "__main__": 5 f([1,2])
函數調用的實參傳遞是經過賦值語句作的,因此傳遞的是object的引用,對於序列這樣的可變類型(mutable),按引用傳遞的話,若是序列作參數在函數體中改變它的值也會影響它在外圍符號表的值,這就像C++中的引用
1 l = ['a', 'b'] 2 def f(l): 3 l.append("22") 4 if __name__ == "__main__": 5 f(l) 6 print l
輸出結果是:
['a', 'b', '22']
3,函數的默認參數
3.1 基礎
函數能夠有默認參數,有默認值的參數必須在沒有默認值的參數後面
1 def f(a, b=5, c="hello"): 2 print c, a+b 3 if __name__ == "__main__": 4 f(3) 5 f(3, 4, "hi")
函數參數的默認值若是取自一個變量,那這個默認值會在函數定義的地方被計算獲得,默認值只會被計算一次
1 i = 6 2 def f(n=i): 3 print n 4 i = 7
會輸出6
3.2當參數的默認值是list這樣的可變對象(mutable object)
函數的默認參數只會被計算一次,無論函數被怎麼調用,因此當參數是list這樣的可變對象時,但在函數體中其值被改變時,再次調用參數的默認值就是改變後的值
1 def f(n, l=[]): 2 l.append(n) 3 print l 4 if __name__ == "__main__": 5 f(1) 6 f(2) 7 f(3)
猜猜看會輸出什麼?輸出
[1]
[1, 2]
[1, 2, 3]
也就是從f(2)調用開始,l的默認值就變了,不會再從新計算一次默認值了。
怎麼避免這樣的狀況呢?用下面的代碼
1 def f(n, l=None): 2 if l is None: 3 l = [] 4 l.append(n) 5 print l 6 if __name__ == "__main__": 7 f(1) 8 f(2) 9 f(3)
輸出結果:
[1]
[2]
[3]
None是個內置常量,固然不能被改變,每次f被調用就會用這個值給l賦值
[問題?]這裏其實我有個待弄明白的問題,默認值是隻會被計算一次仍是參數只會被初始化一次,也就是符號表是每次函數調用都創建和銷燬,仍是函數生存期一直存在,所用調用共用一個。
[答案]如今有答案了,函數的符號表,也就是其局部命名空間會在每次調用和返回時進行建立初始化和刪除。
4,關鍵字實參(keyword argument)
實參(argument)是指函數調用時傳遞進去的參數值(value),區別於形參(parameter)。
Python實參(argument)分爲兩類,關鍵字實參和位置實參(positional argument)。
關鍵字實參就是在調用函數的時候,以name=value的形式傳遞參數,name就是參數定義的名字,也就是形參;關鍵字參數指明瞭參數名,因此能夠不用管其調用時候順序。
位置實參就是隻傳遞value的形式,顧名思義,這要靠實參的位置來匹配形參,關鍵字參數必須位於位置參數以後 。
舉一個簡單的例子
1 def f(a, b, c): 2 print "a =", a, "b =", b, "c =", c 3 if __name__ == "__main__": 4 f(5, c=8, b=2)
輸出結果:
a = 5 b = 2 c = 8
5,參數的解包(unpacking)
若是咱們有一個list或一個dict,可把它直接做爲參數傳給一個函數,裏面的值能夠解包出來傳給一個個參數。
5.1 解包爲位置實參
能夠把一個list或tuple解包,對應的值做爲位置參數傳遞,調用的時候要以*args的形式
>>> range(2,5) [2, 3, 4] >>> args=[2,5] >>> range(*args) #注意調用語法「*args" [2, 3, 4]
range接受兩個參數,給它傳入一個tuple[2,5],解包。
5.2 解包爲關鍵字實參
要解包爲關鍵字參數,使用字典。字典的key爲形參的name,是字符串,字典value爲傳遞的實參。
語法上在調用的時候以**args的形式
使用4小節的例子,輸出結果相同
1 def f(a, b, c): 2 print "a =", a, "b =", b, "c =", c 3 if __name__ == "__main__": 4 d = {"a":5, "c":8, "b":2} 5 f(**d) #注意調用語法「**args"
6,參數的打包,傳遞任意個參數(packing)
可不能夠給函數傳遞任意個參數呢,能夠的,多餘的實參能夠被打包成一個元組(tuple),傳給一個形參。
這個行參在定義時前面加上「*」,即*args
一個小例子,把實參打包成tuple輸出
1 def multiple_argu(*args): 2 print args 3 if __name__ == "__main__": 4 multiple_argu('a', 'b', 'c', 'd')
輸出了一個tuple:
('a', 'b', 'c', 'd')
參考:
http://docs.python.org/3/glossary.html#term-argument Python文檔,術語
http://docs.python.org/2.7/tutorial/controlflow.html#defining-functions Python文檔