11.1.2 返回值與函數類型 python
過程可理解爲函數,返回none web
下面代碼可簡單理解函數返回值的概念: express
>>> defhello(): print "hello world!" >>> res =hello() hello world! >>> printres None >>>type(res) <type'NoneType'> >>> res =hello >>> res() hello world!
另外,與其餘大多數的語言同樣,python 裏的函數能夠返回一個值或者對象。只是在返回一個容器對象的時候有點不一樣,看起來像是能返回多個對象。比如說,你不能拿着大量零散的商品離開百貨店,可是你能夠將它們放在一個購物袋裏,而後帶着這個袋子從商店走出去,合理合法。 編程
>>> def foo(): return["xyz",1000000,-98.6] >>> def bar(): return"abc",[42,"python"], "guido"
foo()函數返回一個列表,bar()函數返回一個元組。因爲元組語法上不須要必定帶上圓括號,因此讓人真的覺得能夠返回多個對象。若是咱們要恰當地給這個元組加上括號, bar()的定義看起來會是這樣: 數組
>>> def bar(): return("abc",[42,"python"], "guido")
固然,加上括號老是好的。咱們能夠這樣接收返回值: 閉包
>>> aTuple = bar() >>> x, y, z = bar() >>> (a, b, c) = bar() >>> aTuple ('abc', [42, 'python'], 'guido') >>> x 'abc' >>> x, y, z ('abc', [42, 'python'], 'guido') >>> (a, b, c) ('abc', [42, 'python'], 'guido')
11.2 調用函數 app
11.2.2 關鍵字參數 框架
關鍵字參數的概念僅僅針對函數的調用。這種理念是讓調用者經過函數調用中的參數名字來區分參數。這樣規範容許參數缺失或者不按順序,由於解釋器能經過給出的關鍵字來匹配參數的值。 dom
例子以下: 函數式編程
>>> def foo(name = "", age = 0): print "name:%s andage:%d" % (name, age) >>> foo(name="fzyz.abc",age=23) name:fzyz.abc and age:23 >>> foo(age=23, name="fzyz.abc") name:fzyz.abc and age:23 >>> foo(age=23) name: and age:23
11.2.4 參數組
固然,你能夠向函數中傳遞沒有顯式定義的參數,用元祖或字典便可。標準格式以下:
func(positional_args,keyword_args,*tuple_grp_nonkw_args, **dict_grp_kw_args)
咱們來簡單看個例子:
from operator import add, sub from random import randint, choice ops = {"+":add, "-":sub} MAXTRIES = 2 def doprob(): op = choice("+-") nums = [randint(1,10) for i inrange(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): break if __name__ == "__main__": main()
程序輸入輸出:
>>> 7 - 1 =6 correct again?[y]y 9 - 5 =4 correct again?[y]n這個程序挺好玩的。
11.3 建立函數
函數是用def 語句來建立的,語法以下:
def function_name(arguments):
"function_documentation_string"
function_body_suite
標題行由def 關鍵字,函數的名字,以及參數的集合(若是有的話)組成。def 子句的剩餘部分包括了一個雖然可選可是強烈推薦的文檔字串,和必需的函數體。
Python中並無函數聲明和定義的區分,由於一般將它們視爲一體。
11.3.5 內部/內嵌函數
在函數體內建立另一個函數(對象)是徹底合法的。這種函數叫作內部/內嵌函數。
>>> def foo(): def bar(): print "bar()called" print "foo() called" bar() >>> foo() foo() called bar() called
>>> class foo(object): def bar(self): print "bar()called" >>> foo().bar() bar() called
11.3.6 *函數(與方法)裝飾器
裝飾器背後的主要動機源自python 面向對象編程。裝飾器是在函數調用之上的修飾。這些修飾僅是當聲明一個函數或者方法的時候,纔會應用的額外調用。
裝飾器的語法以@開頭,接着是裝飾器函數的名字和可選的參數。緊跟着裝飾器聲明的是被修飾的函數,和裝飾函數的可選參數。裝飾器看起來會是這樣:
@decorator(dec_opt_args)
def func2Bdecorated(func_opt_args):
:
爲何會產生裝飾器呢?咱們來看看靜態方法的實現:
class MyClass(object):
def staticFoo():
:
staticFoo = staticmethod(staticFoo)
在這個類的聲明中,咱們定義了叫staticFoo()的方法。如今由於打算讓它成爲靜態方法,咱們省去它的self 參數,self 參數在標準的類方法中是必需的。接着用staticmethod()內建函數來將這個函數「轉化「爲靜態方法,可是在defstaticFoo()後跟着staticFoo = staticmethod (sta- ticFoo)顯得有多麼的臃腫。使用裝飾器,你如今能夠用以下代碼替換掉上面的:
class MyClass(object):
@staticmethod
def staticFoo():
此外,裝飾器能夠如函數調用同樣「堆疊「起來,這裏有一個更加廣泛的例子,使用了多個裝飾器:
@deco2
@deco1
def func(arg1, arg2, ...): pass
這和建立一個組合函數是等價的。
def func(arg1, arg2, ...): pass
func = deco2(deco1(func))
咱們來舉個簡單的裝飾器例子:
class MyClass(object): @staticmethod def the_static_method(x): print x MyClass.the_static_method(2)我本來想寫個複雜的裝飾器程序的,結果寫了半天沒寫出來,我去,我想把裝飾器弄到類裏面來個函數嵌套函數的調用,
有參數和無參數的裝飾器
沒有參數的狀況:
def foo(): pass
....很是的直接
foo = deco(foo)
跟着是無參函數(如上面所見)組成。然而,帶參數的裝飾器decomaker()
@decomaker(deco_args)
def foo(): pass
. . .
須要本身返回以函數做爲參數的裝飾器。換句話說,decomaker()用deco_args 作了些事並返回
函數對象,而該函數對象正是以foo 做爲其參數的裝飾器。簡單的說來:
foo = decomaker(deco_args)(foo)
本身寫不出例子,那麼咱們來看看書本上的例子吧(真的很想經過裝飾器來完成函數調用函數的舉例,不過老是出錯,我去。。。)
這個裝飾器(以及閉包)示範代表裝飾器僅僅是用來「裝飾「(或者修飾)函數的包裝,返回一個修改後的函數對象,將其從新賦值原來的標識符,並永久失去對原始函數對象的訪問。
from time import ctime, sleep def tsfunc(func): def wrappedFunc(): print "[%s] %s()called" % (ctime(), func.__name__) return func return wrappedFunc @tsfunc def foo(): pass foo() for i in range(2): sleep(1) foo()
>>> [Fri Jun 14 20:16:00 2013] foo() called [Fri Jun 14 20:16:01 2013] foo() called [Fri Jun 14 20:16:02 2013] foo() called
11.4 傳遞函數
一個將函數做爲參數傳遞,並在函數體內調用這些函數,更加實際的例子。這個腳本用傳入的轉換函數簡單將一個序列的數轉化爲相同的類型。特別地,test()函數傳入一個內建函數int(),long(), 或者float()來執行轉換。
def convert(func, seq): return [func(eachNum) foreachNum in seq] myseq = (123, 45.67, -6.2e8, 9999999999L) print convert(int, myseq) print convert(long, myseq) print convert(float, myseq)
>>> [123, 45, -620000000, 9999999999L] [123L, 45L, -620000000L, 9999999999L] [123.0, 45.67, -620000000.0, 9999999999.0]
from urllib import urlretrieve def firstNonBlank(lines): for eachLine in lines: if not eachLine.strip(): continue else: return eachLine def firstLast(webpage): f = open(webpage) lines = f.readlines() f.close() print firstNonBlank(lines), lines.reverse() print firstNonBlank(lines) def download(url="http://www.baidu.com", process = firstLast): try: retval = urlretrieve(url)[0] except IOError: retval = None if retval: process(retval) if __name__ == "__main__": download()
程序就是把百度的首頁用HTML的格式輸出。
看得有點頭暈腦脹的,不過繼續看啦。公司竟然斷網了,瞬間無語。。。。
本來休息的時候還能夠寫郵件的,結果一切白談。。。。
11.6 可變長度的參數
11.6.1 非關鍵字可變長參數(元祖)
當函數被調用的時候,全部的形參(必須的和默認的)都將值賦給了在函數聲明中相對應的局部變量。剩下的非關鍵字參數按順序插入到一個元組中便於訪問。
def fun(value1, value2 = "hello", *args): print value1, print value2, for item in args: print item, fun("123","world","1","2","3")程序輸出:
>>> 123 world 1 2 3可是默認參數貌似沒使用成功,先繼續往下看,看默認參數如何和元祖結合使用的。
往下看的時候才知道,若是要用到默認參數的話,必須傳遞的是字典而不是元祖。請看下面的例子:
def fun(value1, value2 = "hello", **args): print value1 print value2 for item in args.keys(): print "key is: %s andvalue is:%s" % (item, str(args[item])) fun("123",value2 = "world", a = 1,b = 2, c = 3)
>>> 123 world key is: a and value is:1 key is: c and value is:3 key is: b and value is:2
fun("123",value2 = "world", "a" =1,"b" = 2, "c" = 3)
想一想就知道了,」a」 = 1自己就是一個錯誤的表達式。
關鍵字和非關鍵字可變長參數都有可能用在同一個函數中,只要關鍵字字典是最後一個參數而且非關鍵字元組先於它以前出現。
我去,這好複雜,複雜的表達式能少用就儘可能少用。
11.6.3 調用帶有可變長參數對象函數
函數式編程舉例
def testit(func, *nkwargs, **kwargs): try: retval = func(*nkwargs,**kwargs) result = (True, retval) except Exception, diag: result = (False, str(diag)) return result def test(): funcs = (int, long, float) vals = (1234, 12.34,"1234", "12.34") for eachFunc in funcs: print "-" * 20 for eachVal in vals: retval =testit(eachFunc, eachVal) if retval[0]: print"%s(%s)=" % (eachFunc.__name__,eachVal), retval[1] else: print "%s(%s) =failed:" % (eachFunc.__name__, eachVal), retval[1] if __name__ == "__main__": test()程序輸出:
>>> -------------------- int(1234)= 1234 int(12.34)= 12 int(1234)= 1234 int(12.34) = failed: invalid literal for int() with base 10: '12.34' -------------------- long(1234)= 1234 long(12.34)= 12 long(1234)= 1234 long(12.34) = failed: invalid literal for long() with base 10: '12.34' -------------------- float(1234)= 1234.0 float(12.34)= 12.34 float(1234)= 1234.0 float(12.34)= 12.34
11.7 函數式編程
來進入傳說中的函數式編程,函數式編程是LISP的核心知識,其實在python中並不過重要,由於python能夠用一些技巧來達到函數式編程的效果,好比列表推導式。
11.7.1 匿名函數與lambda
python 容許用lambda 關鍵字創造匿名函數。匿名是由於不須要以標準的方式來聲明,好比說,使用def 語句。(除非賦值給一個局部變量,這樣的對象也不會在任何的名字空間內建立名字.)然而,做爲函數,它們也能有參數。一個完整的lambda「語句」表明了一個表達式,這個表達式的定義體必須和聲明放在同一行。咱們如今來演示下匿名函數的語法:
lambda [arg1[, arg2,... argN]]: expression
參數是可選的,若是使用的參數話,參數一般也是表達式的一部分。
>>> true = lambda : True >>> true <function <lambda> at 0x020C41F0> >>> true() True
>>> (lambda x, y = 2: x + y)(2,3) 5
11.7.2 內建函數apply(), filter(), map(), reduce()
apply(func[, nkw][,kw])
用可選的參數來調用func,nkw 爲非關鍵字參數,kw 關鍵字參數;返回值是函數調用的返回值。
filter(func, seq)
調用一個布爾函數func來迭代遍歷每一個seq 中的元素; 返回一個使func 返回值爲ture 的元素的序列。
map(func,seq1[,seq2...])
將函數func 做用於給定序列(s)的每一個元素,並用一個列表來提供返回值;若是func 爲None, func 表現爲一個身份函數,返回一個含有每一個序列中元素集合的n 個元組的列表。
reduce(func, seq[,init])
將二元函數做用於seq 序列的元素,每次攜帶一對(先前的結果以及下一個序列元素),連續的將現有的結果和下次給值做用在得到的隨後的結果上,最後減小咱們的序列爲一個單一的返回值;若是初始值init 給定,第一個比較會是init 和第一個序列元素而不是序列的頭兩個元素。
Filter的使用:
def func(num): return num > 5 seq = [1,2,3,4,5,6,7,8,9,10] print filter(func, seq)程序輸出:
>>> [6, 7, 8, 9, 10]
[item for item in seq if item> 5]
>>> map(lambda x,y:x + y, [1,3,5],[2,4,6]) [3, 7, 11] >>> map(lambda x,y:(x+y, x-y), [1,3,5],[2,4,6]) [(3, -1), (7, -1), (11, -1)] >>> map(None,[1,3,5],[2,4,6]) [(1, 2), (3, 4), (5, 6)]這貌似用列表推導式沒法辦到,在多餘兩個參數迭代的狀況下。
Reduce的使用:
reduce(func, [1, 2,3]) = func(func(1, 2), 3)
因此,能夠用reduce垂手可得的進行列表的累加和計算:
>>> reduce(lambda x,y:x + y, range(5)) 10
剛纔看了一下,剛開始以爲神奇,可是忽然想起,這不是LISP裏面lambda最簡單的應用嗎?我一樣能夠用lambda來完成書上的例子:
>>> fun1 = lambda x:x + 1 >>> fun1(4) 5 >>> fun1 = lambda x:int(x, base=2) >>>fun1("10010") 18
偏函數應用GUI
from functools import partial import Tkinter root = Tkinter.Tk() MyButton =partial(Tkinter.Button, root, fg="white",bg="blue") b1 =MyButton(text="button 1") b2 =MyButton(text="button 2") qb = MyButton(text="quit",bg="red",command=root.quit) b1.pack() b2.pack() qb.pack(fill=Tkinter.X,expand=True) root.title("PFAs!") root.mainloop()
其實這裏偏函數的做用就是將一個函數封裝起來,看成參數傳遞罷了。
11.8 變量做用域
11.8.1 全局變量與局部變量
「聲明適用的程序的範圍被稱爲了聲明的做用域。在一個過程當中,若是名字在過程的聲明以內,它的出現即爲過程的局部變量;不然的話,出現即爲非局部的「
全局變量的一個特徵是除非被刪除掉,不然它們的存活到腳本運行結束,且對於全部的函數,他們的值都是能夠被訪問的,然而局部變量,就像它們存放的棧,暫時地存在,僅僅只依賴於定義它們的函數現階段是否處於活動。當一個函數調用出現時,其局部變量就進入聲明它們的做用域。在那一刻,一個新的局部變量名爲那個對象建立了,一旦函數完成,框架被釋放,變量將會離開做用域。
當咱們須要在函數內用到全局變量的時候,能夠用關鍵字global。
11.8.4 閉包
根本就不知道閉包是什麼東東,我去,看例子最重要,從例子中進行理解。
def counter(start_at = 0): count = [start_at] def incr(): count[0] += 1 return count[0] return incr
>>> count =counter(5) >>> count() 6 >>> count() 7 >>> count2 =counter(100) >>> count2() 101 >>> count() 8
咱們來作作練習吧:
11-3 函數。在這個練習中,咱們將實現max()和min()內建函數。
(a) 寫分別帶兩個元素返回一個較大和較小元素,簡單的max2()核min2()函數。他們應該能夠用任意的python 對象運做。舉例來講,max2(4,8)和min2(4,8)會各自每次返回8 和4。
(b) 建立使用了在a 部分中的解來重構max()和min()的新函數my_max()和my_min().這些函數分別返回非空隊列中一個最大和最小值。它們也能帶一個參數集合做爲輸入。用數字和字符串來測試你的解。
a)
def max2(num1, num2): return num1 if num1 > num2 else num2 def min2(num1, num2): return num1 if num1 < num2 else num2 print max2(4,8) print min2(4,8)程序輸出:
>>> 8 4b)
def max2(num1, num2): return num1 if num1 > num2 else num2 def min2(num1, num2): return num1 if num1 < num2 else num2 def my_max(*args): return reduce(max2, args) def my_min(*args): return reduce(min2, args) print my_max(1,2,3,4,5,6,7,8) print my_min(1,2,3,4,5,6,7,8)程序輸出:
>>> 8 1
"""將小時:分鐘形式直接表示爲分鐘格式""" def TranHourToMinute(strTime): num = [] num = strTime.split(":") return int(num[0]) * 60 + int(num[1]) def TranMinuteToHour(strTime): hour,minute = divmod(strTime, 60) return str(hour)+":"+str(minute) if __name__ == "__main__": while True: strTime = raw_input("please enter the time,like 12:12(q to quit):") if strTime.lower() == "q": break print "the time is:%d minutes" % (TranHourToMinute(strTime)) print "the same time is: %s" % (TranMinuteToHour(TranHourToMinute(strTime)))程序輸入輸出:
>>> please enter the time,like 12:12(q to quit):12:12 the time is:732 minutes the same time is: 12:12 please enter the time,like 12:12(q to quit):q
先放着
11–7. 用map() 進行函數式編程。給定一對同一大小的列表, 如[1 , 2 , 3] 和['abc','def','ghi',....],將兩個標歸併爲一個由每一個列表元素組成的元組的單一的表,以使咱們的結果看起來像這樣:{[(1, 'abc'), (2, 'def'), (3, 'ghi'), ...}.(雖然這問題在本質上和第六章的一個問題類似,那時兩個解沒有直接的聯繫)而後建立用zip 內建函數建立另外一個解。
>>> map(lambda x, y:(x, y),[1,2,3],["abc","def","ghi"]) [(1, 'abc'), (2, 'def'), (3, 'ghi')] >>> zip([1,2,3],["abc","def","ghi"]) [(1, 'abc'), (2, 'def'), (3, 'ghi')]
def average(*args): return reduce(lambda x, y: x + y, args) / len(args) print average(1,2,3,4,5)程序輸出:
>>> 3
11–11.用map()進行函數式編程。寫一個使用文件名以及經過除去每行中全部排頭和最尾的空白來「清潔「文件。在原始文件中讀取而後寫入一個新的文件,建立一個新的或者覆蓋掉已存在的。給你的用戶一個選擇來決定執行哪個。將你的解轉換成使用列表解析。
這裏直接用strip方法最簡單,若是非要用map來進行過濾的話,須要本身編寫相似strip的一個函數。
def strip(strTemp): return strTemp.strip() while True: fileName = raw_input("please enter the fileName(q to quit):") if fileName.lower() == "q": break choice = raw_input("n to new file, or c to cover file:") if choice.lower() == "n": newFileName = raw_input("please enter the new file name:") with open(newFileName,"w") as fobj: with open(fileName) as fobjold: lines = fobjold.readlines() for line in map(strip, lines): fobj.write(repr(line)) fobj.write("\n") else: with open(fileName) as fobjold: lines = fobjold.readlines() with open(fileName,"w") as fobjold: for line in map(strip, lines): fobjold.write(repr(line)) fobjold.write("\n")看了一下文件,結果正確。
11–12. 傳遞函數。給在這章中描述的testit()函數寫一個姊妹函數。timeit()會帶一個函數對象(和參數一塊兒)以及計算出用了多少時間來執行這個函數,而不是測試執行時的錯誤。返回下面的狀態:函數返回值,消耗的時間。你能夠用time.clock()或者time.time(),不管哪個給你提供了較高的精度。(通常的共識是在POSIX 上用time.time(),在win32 系統上用time.clock())注意:timeit()函數與timeit 模塊不相關(在python2.3 中引入)
import time def timeit(fun, *args): time1 = time.clock() for i in range(10000000): fun(*args) time2 = time.clock() return time2 - time1 def fun(*args): return reduce(lambda x, y:x + y, args) if __name__ == "__main__": usingTime = timeit(fun, 1,2,3,4,5,6,7,8,9,10) print "using time is: %d" % usingTime程序輸出:
>>> using time is: 19
import time def mult(x, y): return x * y def fac1(n): return reduce(mult, range(1,n)) def fac2(n): return reduce(lambda x, y: x * y, range(1,n)) def timeit(fun, *args): time1 = time.clock() for i in range(1000000): fun(*args) time2 = time.clock() return time2 - time1 print timeit(fac1, 10) print timeit(fac2, 10)程序輸出:
>>> 2.41728863642 2.46803054498
def fib(num): a,b = 1,1 while num - 1: a,b = b,a + b num -= 1 return a def new_fib(num, a = 1, b = 1): if num - 1: a,b = b,a+b return new_fib(num - 1, a, b) else: return a print new_fib(8) print fib(8)不過這裏遞歸用的好醜,可是也不知道該怎麼弄好就是了。
11–15.遞歸。從寫練習6-5 的解,用遞歸向後打印一個字符串。用遞歸向前以及向後打印一個字符串。
def printLeft(strTemp): if strTemp: print strTemp[0], return printLeft(strTemp[1:]) def printRight(strTemp): if strTemp: print strTemp[-1], return printRight(strTemp[:-1]) printLeft("hello world!") print printRight("hello world!")程序輸出:
>>> h e l l o w o r l d ! ! d l r o w o l l e h
我的感受,偏函數就是lambda罷了。
而後迭代器和生成器的區別就是一個運行時候很順利,一個運行時候會一卡一卡的。
PS:異常那章先放在,看得煩躁。