高阶函数
一、编程范式
1、三种编程范式
面向过程:函数封装
面向对象:类封装
函数式:这里的函数是数学上的概念,而不是编程意义上的函数(方法)
2、python的函数式支持
函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数
Python对函数式编程提供部分支持,Python允许使用变量,不是纯函数式编程语言
纯函数式编程意味着没有可变变量、赋值、循环和其他的命令式控制结构
纯函数是这样一种函数,即相同的输入永远会得到相同的输出,而且没有任何可观察的副作用
二、高阶函数
变量可以指向函数
函数名也是变量
把函数作为参数传入,这样的函数称为高阶函数
1、map/reduce
map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果 作为新的Iterator 返回
reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积 计算
str转int方法示例
from functools import reduce
DIGITS = { '0' : 0 , '1' : 1 , '2' : 2 , '3' : 3 , '4' : 4 , '5' : 5 , '6' : 6 , '7' : 7 , '8' : 8 , '9' : 9 }
def str2int ( s) :
def fn ( x, y) :
return x * 10 + y
def char2num ( s) :
return DIGITS[ s]
return reduce ( fn, map ( char2num, s) )
def char2num ( s) :
return DIGITS[ s]
def str2int ( s) :
return reduce ( lambda x, y: x * 10 + y, map ( char2num, s) )
2、filter
filter()也接收一个函数和一个序列,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素
filter()的作用是从一个序列中筛出符合条件的元素,由于filter()使用了惰性计算,所以只有在取filter()结果的时候,才会真正筛选并每次返回下一个筛出的元素
100以内的素数打印
可以用Python表示全体自然数,全体素数这样的序列,代码非常简洁
示例里面就用生成器表示了全体的素数
def odd_iter ( ) :
n = 1
while True :
n = n + 2
yield n
def is_divided ( n) :
return lambda x: x % n > 0
def shushu ( ) :
yield 2
it = odd_iter( )
while True :
n = next ( it)
yield n
it = filter ( is_divided( n) , it)
for i in shushu( ) :
if i < 100 :
print ( i)
else :
break
3、sorted
sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序
对list进行排序,数字直接比较,其他类型需要我们将比较过程通过函数抽象出来
逆序的话可以使用reverse参数
sorted ( [ 'bob' , 'about' , 'Zoo' , 'Credit' ] , key= str . lower, reverse= True )
列表里面嵌套元组的排序
形式是这样的:L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
直接使用sorted的话默认是通过名字进行比较,名字相同通过分数比较
可以定义key函数实现直接通过分数排序,key更准确地说是指定排序的依据
def by_score ( t) :
return - t[ 1 ]
L2 = sorted ( L, key= by_score)
print ( L2)
返回函数
一、函数做返回值
高阶函数除了函数做参数之外,还可以作为返回值
对于返回函数的高阶函数,我们每调用一次,返回的都是新的函数
返回的函数并不会立刻执行,直到调用了f()才执行
二、闭包
内部函数可以引用外部函数的参数和局部变量,当外部函数返回内部函数时,相关参数和变量都保存在返回的函数中,这就是所谓的 闭包
返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量
def outer_fn ( ) :
name = 'allen'
age = 12
def inner_fn ( ) :
print ( '%s : %s' % ( name, age) )
return inner_fn
fn = outer_fn( )
fn( )
匿名函数
就是 lambda 函数,具体的写法是这样的:lambda x: x * x
以 :
分割,前面是输入参数,后面是返回结果
后面的方法体的限制是只能有一个语句,语句的计算结果就是返回值,不用写return
lambda 函数可以做函数的参数和返回值
Python对匿名函数的支持有限,只有一些简单的情况下可以使用匿名函数
装饰器
在代码运行期间动态增加功能的方式,称之为 装饰器 (Decorator)
一、两层嵌套的装饰器
1、基本使用说明
wrapper 里面的return不写,我测试了一下好像是完全没问题的
*args, **kw
可以处理所有的参数
def log ( func) :
def wrapper ( * args, ** kw) :
print ( '20191221' )
return func( * args, ** kw)
return wrapper
@log
def run ( text) :
print ( 'test run !!' + text)
run( "allen" )
2、装饰之后的函数名的变化(__name__
)
原本run方法的__name__
属性的值是run
,但是经过装饰之后就变成了wrapper
__name__
属性的变化会让一些依靠函数签名的代码无法正常工作,可以使用@functools.wraps(func)
来解决这个问题,代码如下
import functools
def log ( func) :
@functools. wraps( func)
def wrapper ( * args, ** kw) :
print ( '20191221' )
return func( * args, ** kw)
return wrapper
@log
def run ( text) :
print ( 'test run !!' + text)
run( "allen" )
print ( run. __name__)
二、三层嵌套的装饰器
def log ( text) :
def decorator ( func) :
def wrapper ( * args, ** kw) :
print ( '%s %s():' % ( text, func. __name__) )
func( * args, ** kw)
return wrapper
return decorator
@log( "haha" )
def run ( ) :
print ( '3 layer test' )
run( )
偏函数
当函数的参数个数太多,需要简化时,使用functools.partial
可以创建一个新的函数,这个新函数可以固定住原函数的部分参数(也就是设置默认值),从而在调用时更简单
注意这里仅仅是设置了参数的默认值而已,我们进行方法调用的时候对该参数还是可以赋值的
示例中函数int的作用是将字符串转化为整数
import functools
int2 = functools. partial( int , base= 2 )
print ( int2( '111' ) )
print ( int2( '111' , base= 10 ) )