Python函数式编程

来源:互联网 发布:淘宝查询礼服秋冬女装 编辑:程序博客网 时间:2024/06/18 06:35

把函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式。

def add(x,y,f):    return f(x)+f(y)print(add(-5,6,abs))

map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。

#mapdef f(x):    return x*xprint(list(map(f,range(10)))) #[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]print(list(map(str,range(10)))) #['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

#reducefrom functools import reducedef add(x,y):    return x+yprint(reduce(add,range(10))) #45def fn(x,y):    return 10*x+y print(reduce(fn,range(10)))#123456789#str2intdef str2int(s):    def fn(x,y):        return 10*x+y    def char2num(s):        return {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s]    return(reduce(fn,map(char2num,s)))print(str2int('3425556'))  #3425556#将英文单词规范化:首字母大写,其余小写L1=['adam','LISA','barT']def stad(s):    temp=s[0].upper()+s[1:].lower()    return tempL2=list(map(stad,L1))print(L2)  #['Adam', 'Lisa', 'Bart']#求乘积def prod(L):    def mul(x,y):        return x*x    return reduce(mul,L3)L3=[3,5,7,9]print('3 * 5 * 7 * 9 =',prod(L3)) #3 * 5 * 7 * 9 = 6561#将字符串转换为floatdef str2float(s):    def char2num(s):        return {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s]    def findpoint(s):        n=0;        for c in s:            if (c=='.'):                break            else:                 n=n+1        return n    def fn(x,y):#计算小数点之前的位数        return 10*x+y    def gn(x,y):#计算小数点之后的位数        return 0.1*x+y    point=findpoint(s)    zhen=reduce(fn,map(char2num,list(s[0:point])))    fen=0.1*reduce(gn,map(char2num,list(s[-1:point:-1])))#此处注意要乘以0.1    return zhen+fenprint(str2float('123.456'))  #123.456#将字符串转换为float 先计算没有小数点的结果,再根据小数点的位置除以相应的数据def str2float(s):    def char2num(s):        return {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s]    def findpoint(s):        n=0;        for c in s:            if (c=='.'):                break            else:                 n=n+1        return n    def fn(x,y):#计算小数点之前的位数        return 10*x+y               point=findpoint(s)    return reduce(fn,map(char2num,list(s[0:point])+list(s[point+1:])))*pow(10,-point)#将两个list相连只需用+即可print(str2float('123.456')) #123.456

filter()接收一个函数和一个序列,把传入的函数依次作用于每个元素,然后只保留使函数返回值是False的元素。

#filter#filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list。def is_odd(n):    return n%2==1print(list(filter(is_odd,range(16))))#将所有偶数过滤掉   [1, 3, 5, 7, 9, 11, 13, 15]#删除序列中的空字符串def not_empty(s):    return s and s.strip()  #strip函数没有参数时默认删掉字符串中的空字符print(list(filter(not_empty,['A',' ','B',None,'C',' ']))) #['A', 'B', 'C']#找出所有的素数def _odd_iter():#生成器,奇数的无限序列    n=1    while True:        n=n+2        yield ndef _not_divisible(n):#筛选函数    return lambda x :x%n>0def primes():    yield 2    it=_odd_iter()# 初始序列    while True:        n=next(it)# 返回序列的第一个数        yield n        it=filter(_not_divisible(n),it)# 构造新序列# 打印1000以内的素数:for n in primes():    if n < 1000:        print(n)    else:        break#找出所有回文数def is_palindrome(n):    s=list(str(n))    s2=s[::-1]    n=0    for i in range(len(s)):        if (s[i]==s2[i]):            n=n+1    return n==len(s)def is_palindrome2(n):  #将n转化成str,与逆转后的str比较是否相等    return str(n) == str(n)[::-1]output=filter(is_palindrome,range(1,1000))print(list(output))output=filter(is_palindrome2,range(1,1000))print(list(output))#[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99, 101, 111, 121, 131, 141, 151, 161, 171, 181, 191, 202, 2#12, 222, 232, 242, 252, 262, 272, 282, 292, 303, 313, 323, 333, 343, 353, 363, 373, 383, 393, 404, 414, 424, 434, 444, 4#54, 464, 474, 484, 494, 505, 515, 525, 535, 545, 555, 565, 575, 585, 595, 606, 616, 626, 636, 646, 656, 666, 676, 686, 6#96, 707, 717, 727, 737, 747, 757, 767, 777, 787, 797, 808, 818, 828, 838, 848, 858, 868, 878, 888, 898, 909, 919, 929, 9#39, 949, 959, 969, 979, 989, 999]

sorted()函数是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序,要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True

#sortedprint(sorted([36, 5, -12, 9, -21], key=abs)) #[5, 9, -12, -21, 36]print(sorted(['bob', 'about', 'Zoo', 'Credit'])) #['Credit', 'Zoo', 'about', 'bob']print(sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower))  #['about', 'bob', 'Credit', 'Zoo']#按照姓名排序L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]def by_name(t):    return t[0]L2=sorted(L,key=by_name)print(L,'\n',L2)#[('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)] [('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)]#按照成绩排序def by_score(t):    return t[1]L3=sorted(L,key=by_score,reverse=True) #[('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Bart', 66)]print(L,'\n',L3)L4=sorted(L,key=by_score) # [('Bart', 66), ('Bob', 75), ('Lisa', 88), ('Adam', 92)]print(L,'\n',L4)

高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。

#返回函数def count():    fs=[]    for i in range(1,4):        def f():            return i*i        fs.append(f) #此处虽然i在每次循环的值都不同,但是因为没有立刻执行函数,所以i的值没有固定,会随着循环而每次都不同    return fsf1,f2,f3=count()print(f1(),f2(),f3())#此时调用函数count,执行f函数,i=3,结果均为9def count2():    def f(i):        def g():            return i*i        return g    fs=[]    for i in range(1,4):        fs.append(f(i))#立刻用不同的i调用函数f,返回值不同    return fsf1,f2,f3=count2()print(f1(),f2(),f3())  #1 4 9

关键字lambda表示匿名函数,冒号前面的x表示函数参数。
匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。
用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数

#匿名函数def build(*args):    def f():        sum=0        for i in args:            sum=sum+i*i        return sum    return fdef build2(x,y):    return lambda:x*x+y*yf1=build(2,3) f2=build2(2,3)print(f1(),f2()) #13 13#使用lambda,x 从 0 迭代到 4 的时候每次都会先赋值给 n;所以 返回的"闭包"中参数n 是绑定的,不会因为 x 的变化而变化squares = []for x in range(5):    squares.append(lambda n=x: n*2)print(squares[2]())#使用之前的返回函数,达到与上述相同的目的squares2 = []def f(x):    def g():        return x*2    return gfor x in range(5):      squares2.append(f(x))print(squares2[2]())"""以下三种结果相同"""def build(x, y):    return lambda: x * x + y * yx = build(3, 6)print(x())def build():    return lambda x, y: x * x + y * yy = build()print(y(3, 6))z = lambda x, y: x * x + y * yprint(z(3, 6))

要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)

#装饰器Decoratorimport functoolsdef now():    print('2017-7-14')def log(func):    @functools.wraps(func)    def wrapper(*args,**kw):        print('call %s():' % func.__name__)#打印日志        return func(*args,**kw)#调用函数    return wrapperdef log2(text):    def decorator(func):        @functools.wraps(func)        def wrapper(*args, **kw):            print('%s %s():' % (text, func.__name__))            return func(*args, **kw)        return wrapper    return decorator@log#相当于执行now = log(now),now变量指向了新的函数,调用时会在log()中返回wrapper()函数def now():    print('2017-7-14')print(now.__name__)  #nowprint(now())  #call_now()  2017-7-14@log2('execute')# now = log('execute')(now),首先执行log('execute'),返回的是decorator函数,再调用返回的函数,参数是now函数,返回值最终是wrapper函数def now2():    print('10:21')print(now2.__name__) #now2print(now2()) #execute now2():  10:21#用一个@log的decorator,使它既支持带参数,也支持不带参数def log(text):    def real_decorator(func):        @functools.wraps(func)        def wrapper(*args, **kw):            if isinstance(text,str): display=text            else:display=''            print('begin call',display)            func()            print('end call')        return wrapper    if isinstance(text,str):        return real_decorator    else:        return real_decorator(text)@log('ext')def f():    print('call f()') #begin call ext   call f()   end call@logdef f1():    print('call f1()')print(f(),'\n',f1())  #begin call   call f1()   end call

偏函数:functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单

#偏函数print(int('1243'))print(int('1243',base=6)) #315 将6进制的‘1243’转化成十进制的int  def int6(x,base=6):    return int(x,base)print(int6('1243'))  #315def int2(x, base=2):#另外定义一个有默认参数的函数,省的每次都设置base的值    return int(x, base) #此处不用return int(x, base=2)是为了代码灵活性,调用int2时也可以传入其他参数print(int2('10001010')) #138print(int2('10001010',6))#280158  调用int2时也可以传入其他参数import functoolsint2=functools.partial(int,base=2)#定义偏函数print(int2('10001010')) #138#但也可以在函数调用时传入其他值桶上面自己定义的int2#偏函数的参数包括函数对象,*args和**kw三个,默认情况下kw = { 'base': 2 }print(int2('1000000', base=10)) #1000000
原创粉丝点击