Python笔记9 函数式编程:匿名函数、高阶函数、装饰器

上一篇中,闭包只是函数式编程的体现之一

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)  来调用

装饰器小结:

  1. 如果想对某个封装单元修改,可以加上装饰器。
  2. 不需要破坏代码实现,易于代码复用。

一个函数能够有多个装饰器。

需要验证身份的函数上加上专门的装饰器之类的用途。

装饰器体现 AOP 思想

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值