上一篇中,闭包只是函数式编程的体现之一
lambda表达式(匿名函数)
lambda parameter_list: expression #没有函数名,没有return
匿名函数的定义与调用:
def add(x, y):
return x + y
f = lambda x,y: x+y #通过变量赋值来定义,实则这是无意义的
print(add(1,2))
print(f(1,2))
#3
#3
lambda中只能进行简单的表达式操作,不能进行赋值操作。
三元表达式
实质为:表达式版本的 if else 语句
格式为:条件为真时返回的结果 if 条件判断 else 条件为假时返回的结果
x = 2
y = 1
r = x if x > y else y
print(r)
#x > y ? x : y #其他语言实现方式
#2
map
基于函数式编程的思想,推荐使用,是一个类
map(函数,序列)
使用场景:把序列中所有值依次传入到函数中,并依次接收返回结果组成一个list;从数学上来看,map 相当于一种映射,将原始列表一一映射到结果列表中
对给定列表的每一项求平方,并存在列表中:
list_x = [1,2,3,4,5,6,7]
def square(x):
return x * x
r = map(square, list_x)
print(list(r))
#[1, 4, 9, 16, 25, 36, 49]
当map 与 lambda 结合使用时,才是正确的打开方式
map与lambda
两者结合,求平方:(函数只有一个参数)
list_x = [1,2,3,4,5,6,7]
r = map(lambda x:x*x, list_x)
print(list(r))
#[1, 4, 9, 16, 25, 36, 49]
非常简洁
传入两个参数列表:
list_x = [1,2,3,4,5,6,7]
list_y = [1,2,3,4,5,6,7]
r = map(lambda x, y : x*x + y, list_x, list_y)
print(list(r))
#[2, 6, 12, 20, 30, 42, 56]
reduce
是一个函数
做连续的计算,连续的调用lambda表达式。
reduce下的函数一定要有两个参数。
from functools import reduce
list_x = [1,2,3,4,5,6,7]
r = reduce(lambda x,y:x + y, list_x)
print(r)
#28
#等价于 ((((((1+2)+3)+4)+5)+6)+7)
继续做什么操作是lambda确定的,不仅只能够相加。
最后一位可以设定初始值,在第一次计算中就进行计算了:
from functools import reduce
list_x = [1,2,3,4,5,6,7]
r = reduce(lambda x,y:x + y, list_x, 10)
print(r)
#38
大数据计算模型:map/reduce编程模型,映射/归约解决并行计算。
python 中函数式编程的重要体现就在于 map、reduce
filter
filter可以过滤掉不符合规则的数据。
剔除序列中的 0 只保留1:
list_x = [1,0,1,0,0,0,1,1]
r = filter(lambda x:True if x == 1 else False, list_x)
print(list(r))
#[1, 1, 1, 1]
filter返回值的要是真和假才能完成过滤(只要可以表示True 和 False即可)
可以简化为:
list_x = [1,0,1,0,0,0,1,1]
r = filter(lambda x: x, list_x)
print(list(r))
#[1, 1, 1, 1]
剔除给定序列中的大写字母:
import re
list_x = ['a', 'A', 'b', 'B', 'C', 'z']
r = filter(lambda x : re.findall('[a-z]', x), list_x)
print(list(r))
#['a', 'b', 'z']
findall 函数如果找不到字母,返回[ ],是False;如果找到小写字母,返回['a']等,是True
命令式编程vs函数式编程
命令式编程涉及到 def if else for
函数式编程涉及到 map reduce(替换循环)、 filter 、lambda(基本单元,对应def)
map reduce filter理论上可以替换def if else for
函数式编程鼻祖:lisp语言,人工智能领域应用较多。
Python是支持函数式编程的,但是本质上是命令式编程,只是部分支持函数式编程
装饰器
用到最多的高阶知识。一些框架比如 Flask 中会大量涉及装饰器
引入:给定一个简单函数:
import time
def f1():
print('This is a function')
f1()
对于如上函数,有一个新的需求,输出时间,修改如下:
import time
def f1():
print(time.time()) #unix 时间戳
print('This is a function')
f1()
#1557226254.0117128
#This is a function
尽管上面的代码实现了功能,但是违背了原则:对修改是封闭的,对扩展是开放的(开闭原则)
同时,如果成百上千的函数有该需求时,加代码很不现实
如下优化:
import time
def f1():
print('This is a function')
def f2():
print('This is a function')
def print_current_time(func): #函数可以作为参数传入
print(time.time())
func()
print_current_time(f1)
print_current_time(f2)
#1557226686.7066443
#This is a function
#1557226686.70715
#This is a function
巧妙的运用函数式编程的思想,将函数作为参数传入,遵守了开闭原则;但不够优雅....并没有将原来的函数与输出时间功能绑定在一起,相当于先输出时间,再执行语句,没有关联性
装饰器就有这种优势:将原来的函数与新功能绑定在一起,体现出是对原函数功能的增加,但是又不修改原函数内部的实现
使用装饰器优化实现如下:
import time
def decorator(func): #装饰
def wrapper(): #被封装
print(time.time())
func()
return wrapper
@decorator #函数之前添加装饰器
def f1():
print('This is a function')
@decorator
def f2():
print('This is a function')
f1()
f2()
#1557227957.0940094
#This is a function
#1557227957.0950105
#This is a function
Python中的装饰器 采用的 AOP 的编程思想
当函数有参数时,wrapper需要传入参数:
import time
def decorator(func):
def wrapper(func_name): #此处若不传入参数,会报错
print(time.time())
func(func_name) #要传参
return wrapper
@decorator
def f1(func_name):
print('This is a function:' + func_name)
f1('test_func')
#1557228383.601304
#This is a function:test_func
装饰器具有通用性,若多个函数接受不同数量的参数,使用可变参数优化:
import time
def decorator(func):
def wrapper(*args): #传入可变参数
print(time.time())
func(*args) #传入可变参数
return wrapper
@decorator
def f1(func_name): #一个参数
print('This is a function:' + func_name)
@decorator
def f2(func_name1, func_name2): #两个参数
print('This is a function:' + func_name1)
print('This is a function:' + func_name2)
f1('test_func')
f2('test_func1', 'test_func2')
#1557228899.3838246
#This is a function:test_func
#1557228899.3843257
#This is a function:test_func1
#This is a function:test_func2
*args不支持**关键字参数
当函数中出现关键字参数时,优化如下:
import time
def decorator(func):
def wrapper(*args, **kw): #添加关键字参数
print(time.time())
func(*args, **kw) #添加关键字参数
return wrapper
@decorator
def f1(func_name): #一个参数
print('This is a function:' + func_name)
@decorator
def f2(func_name1, func_name2): #两个参数
print('This is a function:' + func_name1)
print('This is a function:' + func_name2)
@decorator
def f3(func_name1, func_name2, **kw): #添加关键字参数
print('This is a function:' + func_name1)
print('This is a function:' + func_name2)
print(kw)
f1('test_func')
f2('test_func1', 'test_func2')
f3('test_func1', 'test_func2', a = 1, b = '2', c = '123')
# 1557229295.4020875
# This is a function:test_func
# 1557229295.4020875
# This is a function:test_func1
# This is a function:test_func2
# 1557229295.4030857
# This is a function:test_func1
# This is a function:test_func2
# {'a': 1, 'b': '2', 'c': '123'}
如上,才是装饰器使用的完整方法
在python中,不管函数定义时有几个参数,都可以用 func(*args, **kw) 来调用
装饰器小结:
- 如果想对某个封装单元修改,可以加上装饰器。
- 不需要破坏代码实现,易于代码复用。
一个函数能够有多个装饰器。
需要验证身份的函数上加上专门的装饰器之类的用途。
装饰器体现 AOP 思想