Python闭包装饰器学习笔记[2021/9/18]中秋补班了吗lol

闭包和装饰器
嗨,周六中秋补班,是不是在期待假期呢?然而有些人请假了,觉得很无聊,在家里写笔记了
话不多说,走起~

什么是闭包

 一个能记住嵌套作用域变量值的函数,尽管作用域已经不存在。这种语言现象称之为闭包:

例如函数f1结束了,但是f2仍然能记住x=88;这种情况下,嵌套函数内部会用到外部的变量x。
在这里插入图片描述

什么是装饰器

python语言中,可将函数作为参数传入一个装饰函数,返回另外一个被装饰了的函数;在这个过程中我们对函数添加新的功能;装饰器本身是一个函数或者类;

在学习装饰器的时候,执行以下代码的结果,不是预期的那样,我怀疑自己写错了

import logging
def use_logging(func):
    def wrapper():
        logging.info("%s is running" % func.__name__)
        return func
    return wrapper
@use_logging
def foo():
    print("This is foo")
foo()

执行的结果是 空,于是乎,开始调试代码。在网上找到了以下代码,原来内层的函数需要返回的是函数的调用;
在这里插入图片描述
另外,将上述代码return wrapper 改为 return wrapper(),也会返回报错;原因是@use_logging的语法糖,就是相当于foo = user_logging(foo)。
显然,当执行函数时,装饰器函数就已经调用wrapper函数了,相当于调用func(),此时会执行func,返回值为空;如果return wrapper(),则多了一次函数调用,空类型是无法调用的;报错如下:
在这里插入图片描述
所以正确的装饰器代码如下:

def use_logging(func):
    # print("装饰器嵌套层外")
    def wrapper():
        # logging.info("%s is running" % func.__name__)
        print("%s is running" % func.__name__)
        return func()  # 这里需要是个可调用的函数
    return wrapper 
@use_logging  # foo = user_logging(foo)
def foo():
    print("This is foo")
foo()		# 执行函数foo前,会先执行装饰器

** 以下是带参数的装饰器:**

def use_logging(func):
    def wrapper(name):	# 装饰器返回的函数引用,且可以将函数的参数传入内层函数,形参名称可任意
        print("%s is running" % func.__name__)
        print("decorate %s is running" % name)
        return func(name) 
    return wrapper
@use_logging  # foo = user_logging(foo)
def foo(name):
    print("This is %s" % name)
foo(2) 

带参数的装饰器,且函数的参数名称可以和内层函数的参数名称不一致:

def use_logging(func):
    def wrapper(AGE):
        print("%s is running" % func.__name__)
        print("decorate %s is running" % AGE)
        return func(AGE)  # 这里需要是个可调用的函数
    return wrapper
@use_logging  # foo = user_logging(foo)
def foo(name):
    print("This is %s" % name)
foo(2)

装饰器的执行顺序:
一个函数还可以同时定义多个装饰器,比如:

@a
@b
@c
def f ():
    pass

它的执行顺序是从里到外,最先调用最里层的装饰器,最后调用最外层的装饰器,它等效于
f = a(b(c(f)))

例如

def a(func):
    def wrapper():
        print('iner %s is running' % a.__name__)
        return func()
    return wrapper
def b(func):
    def wrapper():
        print('iner %s is running' % b.__name__)
        return func()
    return wrapper
def c(func):
    def wrapper():
        print('iner %s is running' % c.__name__)
        return func()
    return wrapper
@b
@a
def foo():
    print("foo is running")
foo()

执行结果为:
iner b is running
iner a is running
foo is running

代码注释:
多层的装饰器,相当于foo = b(a(foo)) ,函数执行从外到里,装饰器自下而上;内层返回的是a的wrapper的引用,但是并未执行;
b(wrapper_a)返回的是b的wrapper的引用,但是未执行;当执行foo()时,会执行b_wrapper,相当于执行b中的func(),此时b的func已经被装饰,即为wrapper_a。
相当于先打印a内的一句话,再执行原函数func(打印一句话)

另外,由于先调用装饰器a,在调用装饰器b,所以会先打印a中外层的语句;例如:

def a(func):
    print("outer a")
    def wrapper():
        print('iner %s is running' % a.__name__)
        return func()
    return wrapper
def b(func):
    print("outer b")
    def wrapper():
        print('iner %s is running' % b.__name__)
        return func()
    return wrapper
@b
@a
def foo():
    print("foo is running")
foo()

执行结果就是:
outer a
outer b
iner b is running
iner a is running
foo is running

装饰器的应用

装饰器经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景,装饰器是解决这类问题的绝佳设计。有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码到装饰器中并继续重用。
概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。(此处转载 https://foofish.net/python-decorator.html - 理解 Python 装饰器看这一篇就够了)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值