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
 
 
 

猜你喜欢

转载自www.cnblogs.com/zingerman/p/9985610.html
今日推荐