廖雪峰python3.6教程笔记5-Python基础之函数式编程

函数是Python内建支持的一种封装,把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。

函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。

函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!

一高阶函数

二返回函数

三匿名函数

四装饰器

五偏函数

 

一高阶函数

既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数

例1

 >>> abs(-1)
1
>>> f = abs
>>> f(-1)
1
>>> f
<built-in function abs>
>>> abs = 2
>>> abs(-1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable

例2

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

1 map/reduce函数

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

例3

>>> def f(x):
...     return x*x
>>> r = map(f, [1,2,3,4,5])
>>> r
<map object at 0x1072590f0>
>>> list(r)
[1, 4, 9, 16, 25]

reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算

效果就是:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

例4 

>>> from functools import reduce

>>> def fn(x, y):
...     return x*10+y
>>> reduce(fn, [1,3,5,7,3])
13573
>>> type(reduce(fn, [1,3,5,7,3]))
<class 'int'>

例5

>>> def char2num(s):
...     digits = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
...     return digits[s]
>>> reduce(fn, map(char2num, '13579'))
13579
>>> r = map(char2num, '13579')
>>> list(r)
[1, 3, 5, 7, 9]
>>> type(reduce(fn, map(char2num, '13579')))
<class 'int'>

例6  利用map和reduce编写一个str2float函数,把字符串'123.456'转换成浮点数123.456

from functools import reduce
def str2float(s):
            str2part1 = s.split('.')[0]
            str2part2 = s.split('.')[1]
            def char2num(s):
                        digits = {'0':0, '1':1, '2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8, '9':9}
                        return digits[s]
            def fn1(x,y):
                        return x*10 + y
            def fn2(x,y):
                        return x*0.1 + y
            return reduce(fn1, map(char2num, str2part1)) + reduce(fn2, map(char2num, str2part2[::-1]))*0.1

2 filter函数

Python内建的filter()函数用于过滤,筛选序列。

filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。 

例7: 

>>> def not_empty(s):
...     return s and s.strip()
>>> filter(not_empty, ['A', '', 'B', None, 'C', ' '])
<filter object at 0x10ba9ce80>
>>> list(filter(not_empty, ['A', '', 'B', None, 'C', '  ']))
['A', 'B', 'C']
//注意到filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list。 

例8:回数是指从左向右读和从右向左读都是一样的数,例如12321,909。请利用filter()筛选出回数:

def is_palindrome(n):
    return str(n) == str(n)[::-1]
output = filter(is_palindrome, range(1, 1000)) 

3 sorted函数

sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序。

例8: 

>>> sorted([36, 5, -12, 9, -21])
[-21, -12, 5, 9, 36]
>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]

例9: 

>>> sorted(['bob', 'about', 'Zoo', 'Credit'])
['Credit', 'Zoo', 'about', 'bob']
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
['about', 'bob', 'Credit', 'Zoo']
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True) //进行反向排序
['Zoo', 'Credit', 'bob', 'about']

例10: 假设我们用一组tuple表示学生名字和成绩:

>>> L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
>>> def by_name(t):
...     return t[0]
>>> L2 = sorted(L, key=by_name)
>>> print(L2)
[('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)]
>>> def by_score(t):
...     return -t[1]
>>> L2 = sorted(L, key=by_score)
>>> print(L2)
[('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Bart', 66)]

二返回函数

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

注意:返回一个函数时,牢记该函数并未执行,返回函数中不要引用任何可能会变化的变量。

闭包的简介:https://foofish.net/python-closure.html

 返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

例11

>>> def lazy_sum(*args):
...     def sum():
...         ax = 0
...         for n in args:
...             ax = ax + n
...         return ax
...     return sum
>>> f = lazy_sum(1,3,5,7,9)
>>> f
<function lazy_sum.<locals>.sum at 0x1028efe18>
>>> f()
25
//内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中
三 匿名函数

传入函数时,有时,不需要显式地定义函数,直接传入匿名函数更方便,同时不必担心函数名冲突。

匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数,也可以把匿名函数作为返回值返回。

例12

def is_odd(n):
    return n % 2 == 1
L = list(filter(is_odd, range(1, 20)))
//用匿名函数改造
L = list(filter(lambda x:x%2==1, range(1, 20)))
四 装饰器

这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。decorator可以增强函数的功能,定义起来虽然有点复杂,但使用起来非常灵活和方便。

例13   我们要定义一个能打印日志的decorator 

//import functools
>>> def log(func):
//      @functools.wraps(func)
...     def wrapper(*args, **kw):  //wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。
...         print('call %s():' % func.__name__)
...         return func(*args, **kw)   //在wrapper()函数内,首先打印日志,再紧接着调用原始函数。
...     return wrapper
>>> @log   //借助Python的@语法,把decorator置于函数的定义处,相当于执行了now = log(now)
... def now():
...     print('2018-04-08')
>>> now()  //由于log()是一个decortor,返回一个函数, 原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数,即log()函数返回的wrapper()函数。
call now():
2018-04-08

例14   要自定义log的文本, 3层嵌套的decorator 

// import functools
>>> def log(text):   
//     @functools.wraps(func)     
...     def decorator(func):
...         def wrapper(*args, **kw):
...             print('%s %s():' % (text, func.__name__))
...             return func(*args, **kw)
...         return wrapper
...     return decorator
>>> @log('execute')     //now = log('execute')(now)
... def now():
...     print('2018-04-08')
>>> now()
execute now():
2018-04-08
>>> now.__name__
'wrapper' //经过decorator装饰之后的函数,它们的__name__已经从原来的'now'变成了'wrapper'

例15   请设计一个decorator,它可作用于任何函数上,并打印该函数的执行时间

>>> import time, functools
>>> def metric(fn):
...     @functools.wraps(fn)
...     def wrapper(*agrs, **kw):
...         t0 = time.time()
             result = fn(*args, **kw)  //不过可以在前面执行函数的时候把返回值保存下来最后返回。这样不用重复执行那个函数了
...          //fn(*agrs, **kw)
...         t1 = time.time()
...         print('%s executed in %f ms' % (fn.__name__, (t1 - t0)*1000))
            return result 
...       // return fn(*agrs, **kw)  return 带函数返回,则主程序执行了2次
...     return wrapper  //必须要带返回啊,要不wrapper返回的东西就和加装饰器之前不一样了。 
>>> @metric
... def fast(x, y):
...     time.sleep(0.0012)
...     return x + y;
...
>>> @metric
... def slow(x, y, z):
...     time.sleep(0.1234)
...     return x * y * z;
...
>>> f = fast(11, 22)
fast executed in 1.627 ms
>>> s = slow(11, 22, 33)
slow executed in 125.969 ms
五 偏函数

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

例16

>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('10010')
18

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值