1. 程式人生 > >python從零進階之路——day4

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):
    return
x*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迴圈的資料型別有以下幾種:

一類是集合資料型別,如listtupledictsetstr等;

一類是generator,包括生成器和帶yield的generator function。

這些可以直接作用於for迴圈的物件統稱為可迭代物件:Iterable

可以被next()函式呼叫並不斷返回下一個值的物件稱為迭代器:Iterator

可以使用isinstance()判斷一個物件是否是Iterable或Iterator物件:

集合資料型別如listdictstr等是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