Python 闭包和装饰器


一、python 闭包

1. 什么是闭包

  • Python 函数是支持嵌套的。如果在一个内部函数中对外部函数作用域(非全局作用域)的变量进行引用,那么内部函数就会被称为闭包。
  • 闭包需要满足如下3个条件:
    ① 存在于两个嵌套关系的函数中,并且闭包是内部函数;
    ② 内部函数引用了外部函数的变量;
    ③ 外部函数会返回内部函数的函数名。
def outer(start=0):
    count=[start]
    def inner():
        count[0]+=1
        return count[0]
    return inner
out = outer(5)
print(out())
  • 具体代码走向如下所示
    在这里插入图片描述

2. 示例

  • 演示内置函数
def a():            #1 定义外部函数
    b=1             #3 外部函数代码
    def c():        #4 定义内部函数
        print(b)    #6 执行内部函数的代码
    c()             #5 调用内部函数
a()                 #2 调用外部函数

#输出结果
1
  • 把内部函数返回(闭包的必要条件),使得外部可以用接收返回值的方式来访问内部函数
def a():
    def b():
        return 1    #定义内部函数的返回值为1
    return b        #定义外部函数的返回值为内部函数
rst=a()             #接受外部函数的返回值,也就是内部函数
print(rst)          #rst 就是内部函数
print(rst())        #rst()是调用内部函数
print(a()())        #a()() 和 rst()相同

#输出结果
<function a.<locals>.b at 0x0000028BEE117B80>
1
1
  • 使用一个函数作为另一个函数的参数
def a(func_a):              #可以传任意函数
    print("你好,我是小s!")
    func_a()                #可以对已定义的函数做额外的操作,不需要修改原来的函数
    print("古德拜")

def b():
    print("你好,我是小b!")
a(b)

#输出结果
你好,我是小s!
你好,我是小b!
古德拜
  • 需求:有银行卡才能执行汇款操作
#外:创建银行卡
#内:汇款的操作
#---------------------------------------------------------------------------------------------------------
def bank(isVIP,action):
    if isVIP:
        print("尊敬的会员您好,欢迎光临!")
    else:
        print("您好,给您新办了一张卡!")
    if action=="hui":
        def remit():
            print("汇款操作中")
        return remit
    if action=="cun":
        def cunkuan():
            print("存款操作中")
        return cunkuan

card=bank(False,"cun")
card()
card()
card()

#输出结果
您好,给您新办了一张卡!
存款操作中
存款操作中
存款操作中

二、装饰器

1. 什么是装饰器

  • 假设我们已经定义了一个函数,后续可能会增加临时的需求,例如插入日志,我们可以增加一个包裹函数,由它来负责这些额外的需求,这个包裹函数就是装饰器 。

  • 装饰器是一个函数,它需要接收一个参数,该参数表示被修饰的函数。例如,有如下一个装饰器函数:

def wrap(func):
    print('正在装饰')
    def inner():
        print('正在验证权限')
        func()
    return inner()
  • 装饰器是个嵌套函数,内部函数是一个闭包,外部函数接收的是被修饰的函数(func)

2. 应用场景

装饰器主要用于下列场景:

  • 引入日志
  • 函数执行时间统计
  • 执行函数前预备处理
  • 执行函数后清理功能
  • 权限校验
  • 缓存

3. 示例

  • 通过在函数定义的前面添加@符号和装饰器名,实现装饰器对函数的包装。给下面的函数加上装饰器,示例如下:
from functools import wraps, reduce

def a(func_a):
    print("装饰器开始工作")
    @wraps(func_a)          	#解决被装饰后名字错乱的问题
    def b():
        print("闭包开始工作")
        func_a()
    print("装饰器工作结束")
    return b

@a
def abc():
    print("想要被装饰")
abc()
print(abc.__name__)

#输出结果
装饰器开始工作
装饰器工作结束
闭包开始工作
想要被装饰
abc
  • 多个装饰器应用在一个函数上,调用顺序是从下至上。
def out(args):
    def fun(function_name):
        print('闭包')
        def fun_in():
            print(args)
            return function_name()
        return fun_in
    return fun
fun=out('hello')
@fun
def test():
    print('abc')

a=test()
print(a)

#输出结果
闭包
hello
abc
None

三、常见的 python 内置函数

1. map 函数

  • map函数会根据提供的函数对指定的序列做映射。
  • map函数的定义如下:
map(function, iterable,)
  • 参数function表示函数的名称,参数iterable可以是序列、支持迭代的容器或者迭代器。

  • map函数的作用是以iterable中的每个元素调用function函数,把每次调用后返回的结果保存为迭代器对象。

func = lambda x:x+2
result = map(func, [1,2,3,4,5])
print(list(result))

#输出结果
[3, 4, 5, 6, 7]
  • 执行过程如下

在这里插入图片描述

  • 示例
func=lambda x,y:x+y
rst=map(func,(1,2,3,4,5),[0,7,4,6,8])
for x in rst:
    print(x)

#输出结果
1
9
7
10
13

2. filter 函数

  • filter函数会对指定序列执行过滤操作
  • filter函数的定义如下:
filter(function,iterable)
  • function参数可以是函数的名称或None; iterable参数可以是序列、支持迭代的容器或迭代器。

  • 示例①

func = lambda x:x%2
result = filter(func, [1, 2, 3, 4, 5])
print(list(result))

#输出结果
[1, 3, 5]
  • 执行过程如下
    在这里插入图片描述

  • 示例②

#返回为True的能通过,否则不能通过
func=lambda x:x%2
rst=filter(func,[1,2,3,4,5,6,7,8])
print(list(rst))

#输出结果
[1, 3, 5, 7]

3. reduce 函数

  • reduce 函数会对参数序列中的元素进行累积
  • reduce 函数的定义如下:
reduce(function, iterable[, initializer])
  • function 是一个带有两个参数的函数

  • iterable 是一个迭代器对象

  • initializer 表示固定的初始值

  • 示例,演示 reduce 函数

from functools import reduce

func=lambda x,y:x+y
rst=reduce(func,[1,2,3,4,5,6,7,8,9,10])
print(rst)
#x,y表示前一个值和后一个值,两个值相加

#输出结果
55

注意:
function参数不能为None
在Python 3中,reduce函数已经被从全局名字空间里面移除了,它现在被放置在fucntools模块中,使用时需要先引入
格式如下:
from functools import reduce

总结

  • 闭包
    ① 一个函数包含另一个函数
    ② 外部函数 return了内部函数名
    ③ 内部函数调用了外部函数的变量,这个内部函数叫做闭包

特点
闭包不能直接被调用,而是需要调用外部函数获得返回值;使用该返回值(),来调用内部函数

  • 装饰器

① 在外部函数的参数部分接收函数名
② 在内部函数的函数体中调用参数对应的函数
③ 外部函数返回了内部函数名
④ 调用外部函数传入函数名获取返回值(闭包)
⑤ 通过闭包调用,实现对参数对应的函数调用
⑥ 可以通过@装饰器名,来替代传参的过程

特点
装饰器的调用相对安全可靠,并且不会改变原函数的逻辑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

头发莫的了呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值