Python的装饰器

前言:
    作者简介:我是Morning,计算机的打工人,想要翻身做主人
    个人主页:Morning的主页
    系列专栏::Morning的Python专栏
    如果小编的内容有欠缺或者有改进,请指正拙著。期待与大家的交流
    如果感觉博主的文章还不错的话,点赞 + 关注 + 收藏

目录

一.闭包

1.闭包的必要性

2.定义

3.调用和引用的区别

二.装饰器

1.定义:

2.意义

3.实现方式

4.使用案例

(1)原来思维

(2)使用闭包实现装饰器

三.语法糖

1.简介

2.使用案例

(1)简单的直接使用

(2)有传参

(3)使用函数嵌套进行语法糖传参

3.类与装饰器的使用

(1)装饰类方法

(2)装饰类


一.闭包

在今后的学习中装饰器会起到很大的作用,而装饰器就是基于闭包来实现的

1.闭包的必要性

在一个函数中如果想要想要使用一个变量,我们最直接的方法就是设置一个全局变量。但是这个变量如果只会使用一两次,那么直到代码进行结束前,那个全局变量一直都会占用着资源,不会被销毁,会浪费资源。

2.定义

一个函数中若要用到另一个函数的参数,则可以通过闭包的形式来实行

顾名思义,闭包(封闭包含),在下面这段函数中便能体现出来

def A():
    a=1
    def B():
        b=2
    print(a)

对于函数闭包而言,某一个函数中用到的变量的作用域,取决于其上层或者本层函数函数的作用域。

对于嵌套函数而言,内层函数中定义的变量是无法在外层函数进行使用的(即在B函数中可以调用a,但是不能在A函数中调用b)

此外可以直接调用函数A(),但是不能调用函数B()

3.调用和引用的区别

调用:会直接从内存中去取出相应的对象执行,代码会直接执行

引用:设置了一个路标,该路标指向某一个内存地址中的对象。此时相当于加载了代码在一个缓存空间内,代码并没有被执行。

提醒:如果在没有返回值return的情况下调用闭包函数时,只会调用外层函数,不会调用内层函数

def Student():
    name="susu"
    age=21
    print(f"{name}{age}了")
    def School():
        adress="河北"
        banji=204
        print(name+"在"+adress+"上学")
    return School
s=Student()
print(s)   #结果见图一
def Student():
    name="susu"
    age=21
    print(f"{name}{age}了")
    def School():
        adress="河北"
        banji=204
        print(name+"在"+adress+"上学")
    return School
Student()
School()  #结果见图二
def Student():
    name="susu"
    age=21
    print(f"{name}{age}了")
    def School():
        adress="河北"
        banji=204
        print(name+"在"+adress+"上学")
    return School
Student()() #结果见图三
​
def Student():
    name="susu"
    age=21
    print(f"{name}{age}了")
    def School():
        adress="河北"
        banji=204
        print(name+"在"+adress+"上学")
    return School()
Student()  #结果见图四
​

图一

 

图二

Python的装饰器_第1张图片

图三

Python的装饰器_第2张图片

 

图四:

Python的装饰器_第3张图片

在上面的例子中,School便是引用,School()则是调用。在return School的情况下调用Student函数会发现运行结果中出现的是School函数(即图一);如果调用Student函数的基础上再加个()那么School函数也会被调用(即图三)。

二.装饰器

1.定义:

能够在不改变原有函数的基础上,在原来的基础上添加额外的功能的代码,就叫做装饰器

2.意义

登陆注册(验证账号、密码的准确性)、爬虫中(某一个请求需要在异常之后补充请求头参数然后再去重新对当前请求进行发送)

3.实现方式

对于装饰器的定义,基于函数闭包的形式来实现,即可以将某一个函数作为参数传递给另一个函数,在这另一个函数中去为函数添加功能。

4.使用案例

(1)原来思维

def index():
    print("这里有着大家要的学习资料")
    print("suyuxi")
#对于index而言,它的功能是已经实现了的,不希望重构代码
#(编程都流传着一句话,只要你的程序跑起来,哪怕你知道它有bug那也不要去改哈哈哈)所以登陆的权限就交给了其他的函数来实现
def login(func,username,password):
    if username=="sumaolin" and password=="aisuyuxi":
        func()#传递实参来调用函数
    else:
        print("你无权限,请与管理员联系")
        return 0
login(index,"sumaolin","aisuyuxi")

但是这样的代码可读性并不高。一个函数就添加了三个参数,阅读起来就需要一点一点地去理解,不用说肯定很烦。

(2)使用闭包实现装饰器

那我们有没有一种方法来直接调用index函数呢?那我们就要使用闭包函数来实现装饰器

def index():
    print("这里有着大家要的学习资料")
    print("suyuxi")
#下面便是一个自定义的装饰器。用inner函数来进行修饰func,如果满足条件后再来调用func。从而实现为func添加功能
def login(func):
    username="sumaolin"
    password="aisuyuxi"
    def inner():
        if username == "sumaolin" and password == "aisuyuxi":
            return func()
        else:
            print("你无权限,请与管理员联系")
            return 0
    return inner
login(index)()

此处可能会有人问,为什么不直接返回inner(),而是返回inner。其实两个都能达到我们的目的,只是在此例中我更想突出的是:inner是为了给func添加功能,因此返回的是func函数,然后在对其进行调用

但是说到底我们还是阅读起来不直观,还是需要一步一步地去理解。我们想要一个阅读性更强的代码,那么语法糖就可以解决这个问题

三.语法糖

1.简介

python中去执行修饰器的一种语法规则

写法:@decorator 语法糖都要写在某一个函数定义的头上,表示decorator函数修饰下面的函数

那为什么要去使用它呢。简单理解的话,就是如果你要去修饰一栋墙,你肯定不会是去把墙拆了重新修,而是在之前的基础上进行修饰。代码也是如此,原先的代码我们能不动的话就不动,然后写修饰代码来对原代码进行修饰。

2.使用案例

(1)简单的直接使用

def login(func):   #接收被修饰的对象(对象可以是函数、类、类中的方法)
    username="sumaolin"
    password="aisuyuxi"
    def inner():
        if username == "sumaolin" and password == "aisuyuxi":
            return func()
        else:
            print("你无权限,请与管理员联系")
            return 0
    return inner
#语法糖出现在函数上方,此处表示index函数被装饰器login装饰,login叫做装饰器(n.也叫装饰函数)
#login修饰index的过程是叫装饰函数(v.)
@login
def index():
    print("这里有着大家要的学习资料")
    print("suyuxi")
index()

大家可以看出来除了语法糖的使用外只有调用不同,曾经我都怀疑过是否生效了。

大家仔细看我的注释的话是可以理解的,在外层接受了被装饰的对象index(也可以理解为func是被装饰的对象,即index。所以func就是index)

这样已经可以实现一个比较简单的语法糖了。

(2)有传参

def login(func):   #最外层接收被修饰的对象(对象可以是函数、类、类中的方法)
    username="sumaolin"
    password="aisuyuxi"
    def inner(level):#2
        if username == "sumaolin" and password == "aisuyuxi":
            return func(level)#3
        else:
            print("你无权限,请与管理员联系")
            return 0
    return inner
#语法糖出现在函数上方,此处表示index函数被装饰器login装饰,login叫做装饰器(n.也叫装饰函数)
#login修饰index的过程是叫装饰函数(v.)
@login
def index(level):#4
    print("这里有着大家要的学习资料")
    print("suyuxi")
index(1)#1

在注释中我标注了四个数字。如果我们想要在4处,即我们想要实现的主要代码添加一个形参。那么我们就需要在1处添加实参。但是在调用时3处func的调用肯定也是需要一个形参的,此时的inner又必须与func保持一致,所以2处也必须添加形参。

总的来说,添加一个实参,就需要添加三个形参,说到底我们还是将问题复杂了。

(3)使用函数嵌套进行语法糖传参

但是在进行传参时我们需要注意是不能在装饰器函数设置形参的。最好的方法就是再进行函数的嵌套

def sugar(level):
    def login(func):
        username="sumaolin"
        password="aisuyuxi"
        def inner():
            if username == "sumaolin" and password == "aisuyuxi":
                print(f"您的会员等级为{level}")
                return func()
            else:
                print("你无权限,请与管理员联系")
                return 0
        return inner
    return login
@sugar(3)
def index():
    print("这里有着大家要的学习资料")
    print("suyuxi")
index()

3.类与装饰器的使用

(1)装饰类方法

def decorator(func):
       #print(func)
       def inner():#1
           return func()#2
       return inner
​
class A:
    @decorator
    def hobby(self):
        print("打苏钰烯")
a=A()
a.hobby()

按照我们以前的思想,应该是这么写,但是运行后报错。为了便于理解我们打印一下func到底是什么

Python的装饰器_第4张图片

我们可以看出是类A的实例方法hobby,那么在1和2处我们就需要接受一个self

def decorator(func):
       print(func)
       def inner(self):#1
           return func(self)#2
       return inner
​
class A:
    @decorator
    def hobby(self):
        print("打苏钰烯")
a=A()
a.hobby()

(2)装饰类

def decorator(func):
    def inner():
        return func()
    return inner
@decorator  #该装饰器装饰的是整个类,而不是一个单独的方法,在对类实例化的时候就会调用装饰器
class A:
    def hobby(self):
        print("kkk")
    def love(self):
        print("girl")
a=A()
a.hobby()
a.love()

修饰类的话,那么类中的方法对会被修饰

以上便是我对装饰器的理解,感觉还是不到位,讲解的也十分抽象,因为在实际中的使用还很少。但是会加油的,期待与大家的交流。

还有一位博主的语法糖讲解的比我说的更加条例高效,大家可以看一看(5条消息) Python语法糖装饰器---由浅入深(看一遍就懂系列)_Felix-微信(Felixzfb)的博客-CSDN博客

你可能感兴趣的:(Python,python)