python进阶-- 01 函数式编程
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python进阶-- 01 函数式编程相关的知识,希望对你有一定的参考价值。
1.概念
函数:function,是编程里面的方法
函数式:functional,是一种编程范式
2.特点
把计算视为函数,而非指令
纯函数式编程:不需要变量,没有副作用,测试简单
支持高阶函数,代码简洁
3.python支持的函数式编程
不是纯函数式编程:允许有变量
支持高阶函数:函数可以作为变量传入
支持闭包:有了闭包就能返回函数
有限度的支持匿名函数
4.高阶函数
4.1概念
能接收函数作为变量的函数,称为高阶函数
4.2原理
python中函数名其实是一个变量。
>>> abs(-10)
10
>>> abs=len
>>> abs(-10)
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
abs(-10)
TypeError: object of type ‘int‘ has no len()
>>> abs([1,2,3])
3
4.3举例
>>> def add_ab(x,y,f):
return f(x)+f(y)
>>> add_ab(-5,9,abs)
14
5.返回函数
>>> def f():
print ‘call f()...‘
# 定义函数g:
def g():
print ‘call g()...‘
# 返回函数g:
return g
>>> x=f()
call f()...
>>> x
<function g at 0x0000000002F05A58>
>>> x()
call g()...
6.闭包
6.1概念
内层函数引用了外层函数的变量(外层函数的参数也算变量),然后返回内层函数的情况,称为闭包(Closure)。
6.2特点
返回的函数还引用了外层函数的局部变量;
另外,闭包在定义时,里面的代码未运行,只会在真正被调用时去运行代码,所以运行时取的变量的值为运行时刻(非定义时刻)该变量的值!!!
所以,要正确使用闭包,就要确保引用的局部变量在函数返回后不能变。
重要:默认参数值的获取是在定义时刻!!!
# 希望一次返回3个函数,分别计算1x1,2x2,3x3:
>>>def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
>>> f1()
9
7.匿名函数
7.1举例
lambda x: x * x
等效于
def f(x):
return x * x
7.2特点:
关键字lambda表示匿名函数,冒号前面的一个(多个)变量表示函数参数;
只能有一个表达式,不写return,返回值就是该表达式的结果。
使用匿名函数,可以不必定义函数名
返回函数的时候,也可以返回匿名函数
8.装饰器decorator
8.1背景
已经定义了一个函数,想在运行时动态增加函数功能,又不必去改变函数本身的代码
8.1.1改变源代码
>>> def f1(x):
... print ‘call f1()‘
... return x*2
...
>>> def f2(x):
... print ‘call f2()‘
... return x*x
...
>>> def f3(x):
... print ‘call f3()‘
... return x*x*x
8.1.2使用高阶函数返回新函数
>>> def new_fn(f):
... def fn(*args,**kw):
... print ‘call %s()‘ % f.__name__
... return f(*args,**kw)
... return fn
调用方法有两种:
8.1.3通过内置@自动生成新函数
例
打印日志:@log
检测性能:@performance
数据库事务:@transaction
URL路由:@post(‘/register‘)
8.1.4装饰器概念
Python的 decorator 本质上就是一个高阶函数,它接收一个函数作为参数,然后,返回一个新函数。
8.2无参数装饰器
8.2.1格式
# 定义无参装饰器
def deco_performance(f):
# 定义装饰器中临时函数
def tmp(*args,**kw):
# 执行被装饰函数,可使用有参装饰器所带参数
# xxx
# 返回被装饰函数执行结果
return result
#return f(*args,**kw)
# 返回装饰器中临时函数名
return tmp
8.2.2举例
# 请编写一个@performance,它可以打印出函数调用的时间
def performance(f):
# 要让 @performance 自适应任何参数定义的函数,可以利用Python的
# *args 和 **kw,保证任意个数的参数总是能正常调用
def tmp(*args,**kw):
print "before call--> %s" % (time.time())
# 此刻调用被装饰的函数
result = f(*args,**kw)
print "after call--> %s" % (time.time())
# 只需要返回函数结果,不一定必须要return f(*args,**kw)
return result
# 只是返回函数名
return tmp
# @performance使用
@performance
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
# 使用@performance装饰过的函数的调用
print factorial(10)
8.3有参数装饰器
8.3.1格式
# 定义有参装饰器
def performance(unit):
# 定义无参装饰器
def deco_performance(f):
# 定义装饰器中临时函数
def tmp(*args,**kw):
# 执行被装饰函数,可使用有参装饰器所带参数
# xxx
# 返回被装饰函数执行结果
return result
# 返回装饰器中临时函数名
return tmp
# 返回无参装饰器名
return deco_performance
8.3.2举例
# 定义有参装饰器
def performance(unit):
# 定义无参装饰器
def deco_performance(f):
# 定义装饰器中临时函数
def tmp(*args,**kw):
# 执行被装饰函数,可使用有参装饰器所带参数
print "before call time --> %f" % (time.time() if unit==‘s‘ else time.time()*1000)
result=f(*args,**kw)
print "after call time --> %f" % (time.time() if unit==‘s‘ else time.time()*1000)
print "call %s()" % (f.__name__)
# 返回被装饰函数执行结果
return result
# 返回装饰器中临时函数名
return tmp
# 返回无参装饰器名
return deco_performance
# 使用有(无)参装饰器
@performance(‘s‘)
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
# 调用使用有(无)参装饰器的函数
print factorial(10)
8.4装饰器完善
8.4.1问题
经过@decorator“改造”后的函数,返回的新函数函数名已经被改变,不是‘f2‘,而是@log内部定义的‘wrapper‘。这对于那些依赖函数名的代码就会失效。decorator还改变了函数的__doc__等其它属性。如果要让调用者看不出一个函数经过了@decorator的“改造”,就需要把原函数的一些属性复制到新函数中。
8.4.2完善方法
1.手动在装饰器的临时函数中手动添加属性
def log(f):
def wrapper(*args, **kw):
print ‘call...‘
return f(*args, **kw)
wrapper.__name__ = f.__name__
wrapper.__doc__ = f.__doc__
return wrapper
2.使用python内置的functools装饰器自动完成复制动作
import functools
def log(f):
@functools.wraps(f)
def wrapper(*args, **kw):
print ‘call...‘
return f(*args, **kw)
return wrapper
8.4.3无法避免的问题
最后需要指出,由于我们把原函数签名改成了(*args, **kw),因此,无法获得原函数的原始参数信息。
9偏函数
9.1概念
已经定义了一个函数,函数的参数个数太多,想在运行时动态减少函数必须输入的参数,从而在调用时更简单,实现与默认参数相同的功能,但不改变原本函数。
9.2举例
>>> int(‘12345‘)
12345
>>> int(‘12345‘,8)
5349
>>> int2 = functools.partial(int,base=2)
>>> int2(‘1111‘)
15
9.3注意
创建偏函数时,实际上可以接收函数对象、*args和**kw这3个参数,如果传入xx=xx类型的参数,代表传入kw;如果传入xx类型的参数,会作为args自动加入到参数元组中,需注意是否会影响原本函数应有结果。
>>> max(3,4,5)
5
>>> max2 = functools.partial(max,10)
>>> max2(3,4,5)
10
以上是关于python进阶-- 01 函数式编程的主要内容,如果未能解决你的问题,请参考以下文章
python进阶一(函数式编程)2-1 python把函数作为参数
(转)Python进阶:函数式编程(高阶函数,map,reduce,filter,sorted,返回函数,匿名函数,偏函数)