函數是對程序邏輯進行結構化或過程化的一種編程方法。
Python的函數返回值
當什么也不返回時,返回了None
和大多數語言一樣,Python返回一個值或對象。只是在返回容器對象時,看起來像返回多個對象。
這樣在操作的時候顯得很靈活,雖然它本質上只是反悔了一個對象。
調用函數
我們用一對圓括號電泳函數。任何輸入的參數都應該放在括號中。
關鍵字參數
這個概念是針對函數調用的,比如我們有這樣的函數
def fun(value, count): fun_suite
我們可以標準調用:
fun(12,20)
也可以關鍵字調用
fun(value = 12, count = 20)
或者
fun(count = 20, value =12)
這樣可以豐富調用的方法。另外當參數允許“缺失”的時候,也可以用關鍵字參數。這取決于函數的默認參數。
參數組
Python同樣允許程序員執行一個沒有顯式定義參數的函數,相應的方法是通過一個把元組或字典作為參數傳遞給函數(元組是非關鍵字調用,字典是關鍵字調用)。基本上,可以把所有參數放進一個元組或字典中,僅僅用這些裝有參數的容器來調用一個函數,而不必顯式地將它們放在函數調用中:
func(*tuple_grp_nonkw_args, **dict_grp_kw_args)
其中,tuple_grp_nonkw_args是以元組形式體現的非關鍵字參數組,dict_grp_kw_args是裝有關鍵字參數的字典。這樣的特性允許把變量放在元組和/或字典里,并在沒有顯式地對參數進行逐個聲明的情況下調用函數。
當然也可以給出形參:
func(positional_args, keyWord_args,*tuple_grp_nonkw_args, **dict_grp_kw_args)該語法的所有參數都是可選的,在單獨函數調用時,每個參數都是獨立的。可以有效取代Python1.6以前的apply()內建函數。
如下例:
from Operator import add, subfrom random import randint, choiceops = {'+': add, '-': sub}MAXTRIES = 2def doPRob(): op = choice('+-') nums = [randint(1,10) for i in range(2)] nums.sort(reverse = True) ans = ops[op] (*nums) # *表示后面這個變量是個元組,這一句用了前綴操作符 pr = '%d %s %d = '%(nums[0],op,nums[1]) oops = 0 while True: try: if int(raw_input(pr)) == ans: print 'correct' break if oops == MAXTRIES: print 'answer/n%s%d' %(pr, ans) else: print 'incorrect... try again' oops += 1 except (KeyboardInterrupt, / EOFError, ValueError) : print 'invalid input... try again'def main(): while True: doprob() try: opt = raw_input('Again? [y]').lower() if opt and opt[0] == 'n': break except (KeyboardInterrupt, EOFError): breakif __name__ == '__main__': main()
上面帶有注釋那一行,在Python1.6以前,要寫成apply(ops[op], nums),而不是ops[op](*nums)
創建函數
def語句
語法如下:
def function_name(arguments): "function_documentation_string" function_body_suite
前向引用,要在使用前定義函數。
函數屬性
命名空間與作用域的關系
可以獲得每個Python模塊,類,和函數中任意的名字空間。可以在模塊foo和bar里都有名為x的一個變量,但是在將這兩個模塊導入你的程序后,仍然可以使用這兩個變量。所以,即使在兩個模塊中使用了相同的變量名字,也是安全的,因為句點屬性標識對于兩個模塊意味了不同的命名空間,比如說,在這段代碼中沒有名字沖突:
import foo, barprint foo.x + bar.x
函數屬性是Python另外一個使用了句點屬性標識并擁有名字空間的領域。
名字空間和作用域的關系,在之前的筆記 模塊 這一部分里有詳細敘述。
內嵌函數
在函數體內創建另外一個函數(對象)是完全合法的。這種函數叫做內部/內嵌函數。因為現在Python支持靜態地嵌套域,內部函數實際上是很有用的。
最明顯的創造內部函數的方法是在外部函數的定義體內定義函數,如:
def foo(): def bar(): print 'bar() called' print 'foo() called' bar()foo()bar()
結果是:
foo() calledbar() calledTraceback (most recent call last):File "<pyshell#6>", line 1, in <module>bar()NameError: name 'bar' is not defined
傳遞函數
Python的函數就和其他對象一樣,函數是可以被引用的,也可以作為參數傳入函數,以及作為列表和字典等等容器對象的元素。
函數有個獨一無二的特征使它同其他對象區分開來,那就是函數是可調用的。
因為所有的對象都是通過引用來傳遞的,函數也不例外。當對一個變量賦值時,實際上是將相同對象的引用賦值給這個變量。如果對象是函數的話,這個對象所有的別名都是可調用的。
>>> def foo():print 'in foo()'>>> bar = foo>>> bar<function foo at 0x02B3A0B0>>>> bar()in foo()>>> bar = foo()in foo()>>> bar>>> print bar
當我們把foo賦值給bar時,bar和foo引用了同一個函數對象,所以能以和調用foo()相同的方式調用。foo是函數對象的引用,foo()是函數對象的調用。
同時,函數也可以作為參數傳入其他函數來進行調用
>>> def bar(func):func()>>> bar(foo)in foo()
注意,是將函數對象的引用作為參數,而不是函數對象的調用。
形式參數
Python函數的形參集合由在調用時要傳入函數的所有參數組成,這參數與函數聲明中的參數列表精確的配對。這些參數包括了所有必要參數(如果是標準調用則用正確的定位順序來傳入函數,如果是關鍵字調用則不一定按順序傳入)以及所有含有默認值,函數調用時不必要指定的參數。(聲明函數時創建的)局部命名空間為各個參數值,創建了一個名字,一旦函數開始執行,即能訪問這個名字。
位置參數
位置參數必須以在bewilder調用函數中定義的準確順序來傳遞。另外,沒有任何默認參數的話,傳入函數的參數的精確的數目必須和聲明的數字一致。位置參數也就是我們熟悉的標準化參數
默認參數
對于默認參數,如果在函數調用時我們沒有提供值,就預先使用定義的標準值,如下:
>>> def taxMe(cost, rate=0.0825):return cost + (cost * rate)>>> taxMe (100)108.25>>> taxMe (100, 0.05)105.0
默認參數讓程序的健壯性上升到極高的級別,因為它們補充了標準位置參數沒有提供的一些靈活性。
我們聲明時,所有的必需參數都要在默認參數之前。否則,在混合模式下,解釋器將無法知道如何匹配參數。當然,如果使用關鍵字參數的方式,是可以改換順序的,前提是所有沒給默認值的參數都傳入了值。
可變長度的參數
可能會有需要函數處理可變數量參數的情況。這時可以使用可變長度的參數列表。變長的參數在函數聲明中不是顯式命名的,因為參數的數目在運行時是未知的,這和常規參數(位置和默認)明顯不同,床柜參數都是在函數聲明中命名的。由于函數調用提供了關鍵字以及非關鍵字兩種參數類型,Python用兩種方式來支持變長參數。
非關鍵字可變長參數(元組)
當函數被調用的時候,所有的形參(必須的和默認的)都將值賦給了在函數聲明中對應的局部變量。
剩下的非關鍵字參數按順序插入到一個元組中便于訪問。Python在函數調用時,可以接受一個不定數目的參數。
可變長參數元組必須在位置和默認參數之后,帶元組(或者非關鍵字可變長參數)的函數語法如下:
def function_name([formal_args,] *vargs_tuple): 'function_documentation_string' function_body_suite
星號操作符之后的形參將作為元組傳遞給函數,元組保存了所有傳遞給函數的“額外”的參數(匹配了所有位置和具名參數后剩余的)。如果沒有給出額外參數,元組為空。
在我們之前的函數調用中,如果給出了不正確的函數參數數目,就會產生一個TypeError異常。通過末尾增加一個可變的參數列表變量,我們就能處理當超過數目的參數被傳入函數的情形,因為所有的額外(非關鍵字)參數會被添加到變量參數元組。而和位置參數必須放在關鍵字參數之前一樣的原因,所有的形式參數必須先于非正式參數之前出現。
def tupleVarArgs(arg1, arg2 = 'defaultB', *theRest): 'display regular args and non-keyword variable args' print 'formal arg 1:', arg1 print 'formal arg 2:', arg2 for eachXtrArg in theRest: print 'another arg:', eachXtrArg
運行結果如下:
>>> tupleVarArgs('abc')formal arg 1: abcformal arg 2: defaultB>>> tupleVarArgs(23,4.56)formal arg 1: 23formal arg 2: 4.56>>> tupleVarArgs('abc',123,'xyz',456.789)formal arg 1: abcformal arg 2: 123another arg: xyzanother arg: 456.789
關鍵字變量參數(字典)
在我們有不定數目的或者額外集合的關鍵字的情況中,參數被放入一個字典中,字典中鍵為參數名,值為相應的參數值。
語法為:
def function_name([formal_args,][*vargst,] **theRest): function_documentation_string function_body_suite
為了區分關鍵字參數和非關鍵字非正式參數,使用了雙星號(**)。**是被重載了的一邊不與冪運算發生混淆。關鍵字變量參數應該為函數定義的最后一個參數,帶**。如下例:
>>> def dictVarArgs(arg1,arg2='defaultB',**theRest): 'display 2 regular args and keyword variable args' print 'formal arg1:', arg1 print 'formal arg2:', arg2 for eachXtrArg in theRest.keys(): print 'Xtra arg %s: %s' %/ (eachXtrArg, str (theRest[eachXtrArg]))>>> dictVarArgs(1220,740.0,c='grail')formal arg1: 1220formal arg2: 740.0Xtra arg c: grail>>> dictVarArgs(arg2='tales', c=123, d='poe', arg1='mystery')formal arg1: mysteryformal arg2: talesXtra arg c: 123Xtra arg d: poe
關鍵字和非關鍵字可變長參數都有可能用在同一個函數中,只要關鍵字字典是最后一個參數并且非關鍵字元組先于它之前出現。
調用帶有可變長參數對象函數
將展示一些使用它的例子:
>>> def newfoo(arg1, arg2, *nkw, **kw):'display regular args and all variable args'print 'arg1 is :', arg1print 'arg2 is :', arg2for eachNKW in nkw:print 'additional non-keyword arg:', eachNKWfor eachKW in kw.keys():print "additional keyword arg '%s': %s"%/(eachKW, kw[eachKW])>>> newfoo('wolf',3,'projects',freud=90,gamble=96)arg1 is : wolfarg2 is : 3additional non-keyword arg: projectsadditional keyword arg 'gamble': 96additional keyword arg 'freud': 90>>> newfoo(10,20,30,40,foo=50,bar=60)arg1 is : 10arg2 is : 20additional non-keyword arg: 30additional non-keyword arg: 40additional keyword arg 'foo': 50additional keyword arg 'bar': 60>>> newfoo(2,4,*(6,8),**{'foo':10,'bar':12 })arg1 is : 2arg2 is : 4additional non-keyword arg: 6additional non-keyword arg: 8additional keyword arg 'foo': 10additional keyword arg 'bar': 12>>> aTuple = (6,7,8)>>> aDict = {'z': 9}>>> newfoo(1,2,3,x=4,y=5, *aTuple, **aDict)arg1 is : 1arg2 is : 2additional non-keyword arg: 3additional non-keyword arg: 6additional non-keyword arg: 7additional non-keyword arg: 8additional keyword arg 'y': 5additional keyword arg 'x': 4additional keyword arg 'z': 9
新聞熱點
疑難解答