標籤:運算式 程式員 防偽
防偽碼:忘情公子著
函數是Python為了代碼最大程度地重用和最小化代碼冗餘而提供的基本程式結構。
函數是一種設計工具,能讓程式員將複雜的系統分解為可管理的組件,在需要時能夠按需去調用這些組件。
函數用於將相關功能打包並參數化
在Python中可以建立4種函數:
全域函數:定義在模組中
局部函數:嵌套於其它函數中
lambda(匿名)函數:僅是一個運算式,可以出現在任何位置,使用的靈活度比函數強得多。它產生一個函數對象,若想多次調用,則應將其賦予某變數名進行調用
方法:與特定資料類型關聯的函數,並且只能與資料類型關聯一起使用。說白了就是定義在類(class)中的函數
建立函數,文法如下:
def functionName(parameters): suite
def是一個可執行語句,因此可以出現在任何能夠使用語句的地方,甚至可以嵌套於其它語句,例如if或while中。
def建立了一個對象並將其賦值給一個變數名(即函數名)。
return用於返回結果對象,其為可選;無return語句的函數自動返回None對象。返回多個值時,彼此間使用逗號分隔,且組合為元組形式返回一個對象。
def語句運行之後,可以在程式中通過函數後附加括弧進行調用。如:
In [1]: def printName(): #定義一個函數printName ...: print "hello" ...: In [2]: printName() #調用函數printNamehello
Python建立、改變或尋找變數名,都是在名稱空間中進行的。名稱空間(範圍)說白了就是一個變數所能夠生效的範圍。
在Python中,變數名在程式碼中被賦值的位置,決定了其能夠被訪問到的範圍。
函數定義了本地範圍,而模組定義了全域範圍
每個模組都是一個全域範圍,因此,全域範圍的範圍僅限於單個檔案;
每次對函數的調用都會建立一個新的本地範圍,賦值的變數除非聲明為全域變數,否則均為本地變數;
所有的變數名都可以歸納為本地、全域或內建的(由__builtin__模組提供)
變數名引用分三個範圍進行:首先是本地、之後是函數內、接著是全域,最後是內建。
650) this.width=650;" src="http://s2.51cto.com/wyfs02/M02/8B/CB/wKiom1hY6lCzfHQtAAC9gYEXo40352.jpg" title="函數範圍.jpg" width="700" height="467" border="0" hspace="0" vspace="0" style="width:700px;height:467px;" alt="wKiom1hY6lCzfHQtAAC9gYEXo40352.jpg" />
變數名解析遵循由內而外的法則,也即LEGB原則(如)。變數解析時有幾點需要注意:
先從Local(function)中尋找,找到則返回解析結果,若找不到則到Enclosing function locals中尋找;
若在Enclosing function locals中找到了則返回解析結果,若找不到則到Global(module)中尋找;
若在Global(module)中找到了則返回解析結果,若找不到則到Built-in中尋找;
若在Built-in中找到了則返回解析結果,若找不到則返回“名稱引用錯誤”異常
變數名解析時,範圍越小,其優先順序越高。也就是說,若在Local(function)中找到了,則直接返回其解析結果,而不會再到Enclosing function locals上去尋找了。
全域變數:
全域變數是模組檔案內部的頂層變數名;
如果要在函數內部對全域變數進行賦值的話,必須事先使用global進行聲明,global關鍵字後跟一個或多個由逗號隔開的變數名;
全域變數名在函數內部不經聲明也可以被引用;
本地變數在函數返回時會消失,而全域變數不會,因此,使用全域變數是儲存函數狀態資訊的最直接辦法;
盡量避免在函數中使用global聲明全域變數。
內嵌函數:
Python中函數可以嵌套,也即可以在一個函數內部定義一個函數;
在函數內部定義的函數僅能由外層函數進行調用;
而如果外層函數直接把內層函數使用return返回,則調用外層函數時賦值的變數名引用的是一個內層函數對象,且此內層函數能夠記憶其內部引用的外層函數的變數,這種行為叫做工廠函數,也叫閉合函數
In [11]: def maker(N): ...: def action(X): ...: return X ** N ...: return action ...:In [12]: f = maker(2)In [13]: f(3)Out[13]: 9In [14]: f(4)Out[14]: 16In [15]: type(f)Out[15]: function
參數傳遞:
參數的傳遞是通過自動將對象賦值給本地變數實現的
650) this.width=650;" src="http://s1.51cto.com/wyfs02/M02/8B/C8/wKioL1hY9h-wG3iAAAAxe5nkG6Y156.jpg" title="參數傳遞.jpg" alt="wKioL1hY9h-wG3iAAAAxe5nkG6Y156.jpg" />
不可變參數通過“值”進行傳遞,在函數內部改變形參的值,只是讓其引用了另一個對象(如數字)
可變參數通過“指標”進行傳遞,在函數內部改變形參的值,將直接修改引用的對象(如列表)
有兩種方式可避免可變參數被函數修改:
1、直接傳遞可變對象的副本:
In [16]: L = [1,2,3,4]In [17]: def changer(X): ...: X[2]+=10 ...: return X ...:In [18]: changer(L[:])Out[18]: [1, 2, 13, 4]In [19]: print L[1, 2, 3, 4]
2、在函數內部建立可變參數的副本
In [27]: L = [1,2,3,4]In [28]: def changer(X): ...: aa = X[:] ...: aa[2]+=10 ...: return aa ...:In [29]: changer(L)Out[29]: [1, 2, 13, 4]In [30]: print L[1, 2, 3, 4]
參數匹配模型:
預設情況下,參數通過其位置進行傳遞,從左至右,這意味著,必須精確地傳遞和函數頭部參數一樣多的參數
但也可以通過關鍵字參數、預設參數或參數容器等改變這種機制
位置:從左至右
關鍵字參數:使用“name=value”的文法通過參數名進行匹配
預設參數:定義函數時使用“name=value”的文法直接給變數一個值,從而傳入的值可以少於參數個數
可變參數:定義是為了整合,調用是為了分解
定義函數時使用*開頭的參數,可用於收集任意多基於位置的參數:
In [31]: def test(*x): ...: print x ...: In [32]: test(1)(1,)In [33]: test(1,2,3)(1, 2, 3)
定義函數時使用**開頭的參數,可用於收集任意多基於關鍵字參數,並將其轉換成字典:
In [34]: def dict(**x): ...: print x ...: In [35]: dict(x=1,y=2,z=6){‘y‘: 2, ‘x‘: 1, ‘z‘: 6}
混用位置參數與可變參數:
In [36]: def a(x,*y): ...: print x,y ...: In [37]: a(1,2,3,4)1 (2, 3, 4)
In [38]: def b(*x,**y): ...: print x ...: print y ...: In [39]: b(1,2,3,4,5,i=3,j=9,c=5)(1, 2, 3, 4, 5){‘i‘: 3, ‘c‘: 5, ‘j‘: 9}
可變參數解包:調用函數時,使用*開頭的參數,可用於將參數集合打散,從而傳遞任意多基於位置或關鍵字的參數。可以理解為分解參數。
變數分解賦值:
In [1]: l1 = [‘Sun‘,‘Mon‘,‘Tue‘]In [2]: x,y,z = l1In [3]: print xSunIn [4]: print yMonIn [5]: print zTue
In [6]: l2 = [‘Sun‘,‘Mon‘,‘Tue‘]In [7]: def a(x,y,z): ...: print x,y,z ...: In [8]: a(*l2)Sun Mon Tue
可變參數與位置參數混合使用時,不論是定義還是調用,均使用以下順序:
位置參數-->任意位置參數(*)-->關鍵字參數(**)
匿名函數lambda:
文法如下:
lambda args: expression
args:以逗號分隔的參數列表
expression:用到args中各參數的運算式
lambda語句定義的代碼必須是合法的運算式,不能出現多條件陳述式(可使用if的三元運算式)和其它非運算式語句,如for和while等。
lambda的首要用途是指定短小的回呼函數。lambda將返回一個函數而不是將函數賦值給某變數名。
注意:
lambda是一個運算式而非語句;
lambda是一個單個運算式,而不是一個代碼塊
In [9]: lambda x,y: print x,y #不能是語句,只能是運算式 File "<ipython-input-9-323c5186b793>", line 1 lambda x,y: print x,y ^SyntaxError: invalid syntaxIn [10]: lambda x,y: x + y #返回的是一個函數Out[10]: <function __main__.<lambda>>
因為lambda返回的是一個函數,所以如果要調用它的話,則要將lambda運算式賦予一個變數名,通過變數名來調用:
In [11]: a = lambda x,y: x + yIn [12]: a(5,6)Out[12]: 11
正因為lambda函數調用時必須賦予給某個變數名,通過變數名來調用,而這個變數名又不固定,故此稱之為匿名函數。
def語句建立的函數將賦值給某變數名,而lambda運算式則直接返回函數。lambda也支援使用預設參數。
In [13]: def testFunc(x,y,z): ...: return x + y + z ...:In [14]: testFunc(4,5,6)Out[14]: 15In [15]: f = lambda x,y,z: x+y+zIn [16]: f(4,5,6)Out[16]: 15In [17]: f2 = (lambda x,y,z=10: x+y+z)In [18]: f2(4,5)Out[18]: 19
在對某個資料對象作出多種不同處理時,可以把每一種處理機制定義成一個lambda,而後對這個資料對象調用這多個lambda運算式。
In [1]: l3 = [ (lambda x: x*2),(lambda y: y*3) ]In [2]: for i in l3: #i取到的是lambda運算式,而不是x和y的值 ...: print i(4) ...: 812
本文出自 “忘情博” 部落格,請務必保留此出處http://itchentao.blog.51cto.com/5168625/1884653
python之函數