照着廖雪峰的网站做笔记
高阶函数Higher-order function
变量可以指向函数,函数的参数能接收变量,若一个函数接收另一个函数作为参数,这种函数称之为高阶函数。
以下的介绍要注意,函数作为参数传递的时候只有函数的名字这个变量,不能加括号,自然不能在括号内加上参数名,加了括号就执行了,所以不能加括号!!
map
map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。(注意:iterable就行,不一定是iterator,但是使用map函数的返回值就一定是iterator)
def f(x):
return x * x
r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
list(r)
结果(r是个iterator,要用list()函数把他计算出来)
[1, 4, 9, 16, 25, 36, 49, 64, 81]
用法:map(func_name,interable)
reduce
reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
用之前要from functools import reduce
def sum(a,b):
return a+b
c=reduce(sum,[1,2,3,4,5])
print(c)#结果是15,也可以写成:
c=reduce(lambda x,y:x+y,[1,2,3,4,5])
print(c)#结果还是15
filter
用于设定条件,过滤序列。跟map一样,filter接收2个参数。一个是函数名字,一个是序列,返回结果是一个iterator。
用法:filter(func_name.iterable)
其中func_name函数返回值应该为true or false,这个函数分别作用于序列的每一个,若返回true,留着;若返回false,舍弃,最后生成一个iterator(不做计算,调用的时候再计算)。
def a(x):
return x%2!=0
b=filter(a,[1,2,3,4,5,6,7,8,9])
print((list(b)))
#结果:
[1, 3, 5, 7, 9]
sorted
python内置的,可以直接用sorted(序列),此外sorted()也是一个高阶函数,可以接受一个key(key是个函数名字,这个函数分别作用于序列的每一项,然后把处理后的结果排序)
如
print(sorted([36, 5, -12, 9, -21], key=abs))#结果为:
[5, 9, -12, -21, 36]
函数作为返回值
python中函数当然可以作为另一个函数的返回值返回,一开始我觉得这理所当然,但是为什么要这么做呢?直接把这个函数的功能写在里面就行了嘛。后来看了装饰器的部分才理解,函数作为返回值的目的就是:
把功能先定义好,但是不执行,调用的时候再执行。
但是于一般的函数有点区别:一般函数只要输入固定,返回值就一定是一样的,但是函数作为返回值的话,输入一样的参数,返回的函数虽然功能一样,但是却不是一个函数,地址也不一样,分别调用2个函数互相不影响。
def sum(x,y):
def sum2():
return x+y
return sum2
a=sum(2,3)
b=sum(2,3)
print(a)
print(b)
print(a())
print(b())
结果:
<function sum.<locals>.sum2 at 0x00000232A7505288>
<function sum.<locals>.sum2 at 0x00000232A7505318>
5
5
闭包closure
上面sum2函数中用了x,y,但是它们没有在sum2中定义,也没有作为sum2函数的参数,而是用了外层sum函数的参数。这种用了外层函数参数和外层函数局部变量的函数,就是内部的这个函数,叫做闭包。
闭包每次运行是能够记住引用的外部作用域的变量的值。
闭包不能引用循环变量和后续可能会变化的变量。
匿名函数
用法lambda a,b,c : a+b*c
lambda接着是函数参数,接着是冒号,再接着是一个表达式,这个匿名函数的返回值就是表达式的值。
记住lambda是一个函数,也是一个对象,跟普通函数一样的用法
如:a=lambda x : x*x
或者a=(lambda x : x*x)(3)
前者返回的是一个函数对象,后者直接执行了,结果是9。
装饰器decorator
这部分看起来好理解,但是真正搞懂还是用了点时间,练习了几个例子。装饰器的目的是不动原来的函数,在这个函数的前后做一些操作,比如在前后加日志,把结果平方一下等等。
装饰器是一个函数,是一个把另一个函数作为参数,然后返回另一个函数变量的一个函数
。
格式是这样的:
def decorator(func):
def wrapper(*args,**kws):
statements...
func(*args,**kws)
statements...
return wrapper
@decorator
def sum(x,y):
return x+y
理解步骤如下:
- 装饰器是一个函数,参数是个函数,返回值是另一个函数,于是就有
decorator(func)
这个函数,返回值是另一个函数wrapper
- 下面我们定义将要被返回的这个函数,叫它wrapper吧,它的参数是
(*args,**kws)
,因为内部执行你传入的那个func函数的时候要用。你返回的就是wrapper函数,调用的时候实际上就是wrapper(x,y)
,这样把x,y传进去,内部的func函数才能执行。 - 这个
wrapper
函数怎么定义就随便你了,可以先打印一行日志再执行func函数,然后没有返回值;也可以执行了func函数以后,返回func结果的平方。
把@decorator
放在def sum(x,y):
这个地方,相当于:
sum=decorator(sum)
所以decorator的参数必须为func
。而wrapper
函数的参数看实际情况,我认为写成(*args,**kws)
这种形式只是为了方便,这样不管要装饰的函数有什么参数都可以传进去,如果没有参数你当然也可以不写。
如果装饰器本身也需要传入参数,比如日志内容啥的,怎么办?就再刚刚上面的外部,再加一个函数,这个刚加的函数就是接收参数用的。
def log(name)
def decorator(func):
def wrapper(*args,**kws):
print(name)
func(*args,**kws)
statements...
return wrapper
return decorator
@log('john')
def sum(x,y):
return x+y
这就相当于:sum=log('john')(sum)
。里面该啥样还是啥样。
为了保持装饰前后函数的__name__等属性不变,所以加入@functools.wraps(func)
from functools import wraps
def decorator(func):
@wraps(func)
def wrapper(*args,**kws):
statements...
func(*args,**kws)
statements...
return wrapper
举例说明,下面写了4个装饰器:
def log1(func):#只是加了一个打印一行字的功能
@wraps(func)
def wrapper(*args,**kwargs):
print('working...')
return func(*args,**kwargs)#func加了括号,在返回这执行了
return wrapper
def log2(name):#装饰器带了参数,所以外边加了一层
def decorator(func):
@wraps(func)
def wrapper(*args,**kwargs):
print(name)
print('working...')
return func(*args,**kwargs)
return wrapper
return decorator
def log3(name):#试试对函数结果做平方处理的装饰器
def decotator2(func):
@wraps(func)
def wrapper(*args,**kwargs):
print(name)
print('working...')
a=func(*args,**kwargs)
return a*a
return wrapper
return decotator2
def log4(func):#只要返回wrapper函数就行,wrapper不一定有返回值
@wraps(func)
def wrapper(*args,**kwargs):
print('working...')
a=func(*args,**kwargs)#不一定非要在返回那里执行,在中间执行也可以
print(a)
print('done')
return wrapper
分别装饰一个求和函数,看结果:
@log1
def sum(x,y):
return x+y
a=sum(2,3)
print(a)
print(sum.__name__)#结果: working 5 sum
@log2('john')
def sum(x,y):
return x+y
a=sum(2,3)
print(a)
print(sum.__name__)#结果:john working 5 sum
@log3('john')
def sum(x,y):
return x+y
a=sum(2,3)
print(a)
print(sum.__name__)#结果:john working 25 sum
@log4
def sum(x,y):
return x+y
# a=sum(2,3)
# print(a)
sum(2,3)
print(sum.__name__)#结果:working 5 done sum
**偏函数 partial **
函数functools.partial
可以创建偏函数,它的第一个参数是一个函数对象,剩下的参数就一一对应着传入那个函数的各个参数。就可以通过指定某些参数的值来创建一个固定部分参数值的新函数。用起来更方便。
如,创建一个100除以一个数的函数
from functools import partial
def devide(x,y):
return x/y
a=partial(devide,100)
print(a(2))
#结果:50.0
如果:
def devide(x,y):
return x/y
a=partial(devide,100,50)
print(a())
#结果为2.0
如果原函数有关键字参数,可以直接指定关键字参数的值。
from functools import partial
def cal(x,y,sum=False,mul=False):
if sum==True:
return x+y
if mul==True:
return x*y
a=partial(cal,mul=True)
print(a(4,5))
#结果为20
partial这个函数后面的参数一定要注意顺序。
map,reduce,partial等等这些把函数作为参数传入的时候,只需要传入函数的名字!!不用带括号和参数。