python從零進階之路——day4
高階函式
函式在記憶體中儲存方式跟變數一樣,計算機會為函式開闢記憶體空間存放函式體,同時函式名指向這個記憶體空間,函式名相當於控制代碼(記憶體地址),函式可以賦值給變數,通過變數呼叫,函式與變數一樣也可以作為引數傳給另一個函式。
把函式作為引數傳入,這樣的函式稱為高階函式,函數語言程式設計就是指這種高度抽象的程式設計正規化。
# author:zingerman def add(x,y,func): print(func(x)+func(y)) add(2,-3,abs)#abs是絕對值函式的控制代碼,指向記憶體中的函式體,func==abs , func()==abs()
高階函式之map函式
#map()函式接收兩個引數,一個是函式,一個是Iterable # map將傳入的函式依次作用到序列的每個元素,並把結果作為新的Iterator返回。 def f(x): return x*x r=map(f,[1,2,3,4]) #<map object at 0x000001E7E456FF28>返回結果的記憶體地址 print(list(r)) #[1, 4, 9, 16]
也可以這樣:
def f(x,y): return x*y r=map(f,[1,2,3,4],[1,2,3,4]) #<map object at 0x000001E7E456FF28>返回結果的記憶體地址print(list(r)) #[1, 4, 9, 16]
一段程式碼將裂變轉化成字串
高階函式之reduce函式
reduce
把一個函式作用在一個序列[x1, x2, x3, ...]
上,這個函式必須接收兩個引數,reduce
把結果繼續和序列的下一個元素做累積計算,其效果就是
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
# author:zingerman from functools import reduce #結果24,相當於sum 函式 def f (x,y): returnx*y print(reduce(f,[1,2,3,4]))
from functools import reduce def f (x,y): return x*10+y print(reduce(f,[1,2,3,4])) #將[1,2,3,4]轉換成1234
def func(x,y): return x*10+y def char2num(s): digter={'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9} return digter[s] print(list(map(char2num,'12345'))) #[1, 2, 3, 4, 5] print(reduce(func,map(char2num,'12345'))) #12345 相當與int()函式
from functools import reduce #簡化版str2int函式 DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9} def char2num(s): return DIGITS[s] def str2int(s): return reduce(lambda x, y: x * 10 + y, map(char2num, s))
高階函式之filter函式
filter()
把傳入的函式依次作用於每個元素,然後根據返回值是True
還是False
決定保留還是丟棄該元素。
# author:zingerman #使用filter判斷是不是奇數,並保留 def is_odd(n): return n%2==1 print(list(filter(is_odd,[1,2,3,4,5,6])))#[1, 3, 5]
filter()
函式返回的是一個Iterator
,也就是一個惰性序列,所以要強迫filter()
完成計算結果,需要用list()
函式獲得所有結果並返回list
裝飾器(Decorator) 高階函式+巢狀函式==》》裝飾器
本質:一個返回函式的高階函式
作用:為其他函式新增附加功能
原則:1.不能修改被裝飾函式的原始碼
2.不能修改被裝飾函式的呼叫方式
實現裝飾器的知識儲備:
1.函式即"變數"
2.高階函式
3.巢狀函式
# author:zingerman import time def deco(func): start_time=time.time() func() end_time=time.time() print('花費的時間%s'%(end_time-start_time)) def test(): time.sleep(1) print('in the test') deco(test)#將test賦值給func,增加了功能,沒有改變test的原始碼,但是改變了函式的原本呼叫方式test()
# author:zingerman import time def deco2(func):#deco2(test) func=test deco2函式的目的就是定義deco1函式,並拿到deco1的記憶體地址 def deco1(): start_time=time.time() func() end_time=time.time() print('花費的時間%s'%(end_time-start_time)) return deco1 def test(): time.sleep(1) print('in the test') test=deco2(test) #想要以test()這種呼叫方式實現附加功能而不改變test原始碼, test() # 只有把deco1賦值給test,然後test()執行,現在的test是加了新功能的deco1 #所以將deco1巢狀入deco2函式,並返回deco1,這樣就拿到了deco1的記憶體地址
# author:zingerman import time def deco2(func):#deco2(test) func=test deco2函式的目的就是定義deco1函式,並拿到deco1的記憶體地址 def deco1(): start_time=time.time() func() end_time=time.time() print('花費的時間%s'%(end_time-start_time)) return deco1 @deco2 #相當於test=deco2(test) def test(): time.sleep(1) print('in the test') test()
# author:zingerman import time #帶引數的裝飾器 def deco2(func): def deco1(*args,**kwargs): start_time=time.time() func(*args,**kwargs) end_time=time.time() print('花費的時間%s'%(end_time-start_time)) return deco1 @deco2 #相當於test=deco2(test) def test(x): time.sleep(1) print(x) print('in the test') test(2)
生成器:
python使用生成器對延遲操作提供支援,延遲操作就是在有需要的地方產生結果,而不是立即產生結果
python有兩種方法提供生成器:
1.生成器函式:常規函式定義,但是使用yield而不是return返回結果,yield語句每次返回一個結果,之後掛起函式的狀態,以便下次從yiled之後開始執行,相當於在yield處產生了一箇中斷
# author:zingerman def fib (n): #用生成器產生斐波那契數列 a, b = 0, 1 for i in range(n): yield (b) a,b=b,a+b #=fib(10) for i in fib(10): print(i)
2.生成器表示式:類似於列表推導,但是生成器一次產生一個結果,而不是一次就產生一個列表,儲存所有結果。 (x**2 for x in range(5))
python中的很多內建函式都是用了迭代器協議去訪問物件,而生成器實現了迭代器物件,如for函式,sum函式
>>> sum(x ** 2 for x in xrange(4))
而不必這樣寫>>> sum([x ** 2 for x in xrange(4)])
# author:zingerman import time def consume(name): print('%s準備吃包子了'%name) while True: baizi=yield print('%s包子來了,被%s吃了'%(baizi,name)) # f=consume('hulida') # f.__next__() # f.send('韭菜餡') def producer(name): c1 = consume('A') c2 = consume('B') c1.__next__() c2.__next__() print("老子開始準備做包子啦!") for i in range(10): time.sleep(1) print("做了1個包子,分兩半!") c1.send(i) c2.send(i) producer('hu')
迭代器:
我們已經知道,可以直接作用於for
迴圈的資料型別有以下幾種:
一類是集合資料型別,如list
、tuple
、dict
、set
、str
等;
一類是generator
,包括生成器和帶yield
的generator function。
這些可以直接作用於for
迴圈的物件統稱為可迭代物件:Iterable
。
可以被next()
函式呼叫並不斷返回下一個值的物件稱為迭代器:Iterator
可以使用isinstance()
判斷一個物件是否是Iterable或
物件:Iterator
集合資料型別如list
、dict
、str
等是Iterable
但不是Iterator
,不過可以通過iter()
函式獲得一個Iterator
物件
from collections import Iterable >>> isinstance([], Iterable) True >>> isinstance({}, Iterable) True >>> isinstance('abc', Iterable) True >>> isinstance((x for x in range(10)), Iterable) True >>> isinstance(100, Iterable) False
>>> from collections import Iterator >>> isinstance((x for x in range(10)), Iterator) True >>> isinstance([], Iterator) False >>> isinstance({}, Iterator) False >>> isinstance('abc', Iterator) False