装饰器

要想明白装饰器,得先明白闭包,所以什么是闭包呢?

闭包的原则:

  1、函数中嵌套函数

  2、外层函数返回内层函数名

  3、内层函数引用外层函数的非全局变量

闭包的作用:

  实现对数据的锁定,提高稳定性

那么下面来实现一个闭包函数吧

1 def fun():
2     a = 2
3     def add():
4         print(a)
5     return add

那么可以看出以上函数是满足闭包的原则的

  1、函数中嵌套函数

  2、外层函数返回内层函数名

  3、内层函数引用外层函数的非全局变量

所以上面的fun函数是一个闭包函数

现在已经理解了闭包了,那么接下来来说说装饰器

装饰器其实和闭包差不多,因为在实际的开发过程中,要遵守一个原则,那就是开放封闭原则,这是什么意思呢?也就是说已经实现的功能,我们不能去改变其内部代码结构,但是可以扩展,这就是开放封闭原则

列如,我们现在有一个展示首页的函数

1 def shouye():
2     print("这个是网站的首页")

现在增加了一个需求,在展示首页之前必须得先登陆之后才能看得到首页,不然不能看到,由于开放封闭原则我们不能去动这个shouye函数了,所以只能采用装饰器来实现

所以我们需要写一个登陆的脚本

 1 def login(func):
 2     def fun():
 3         username = "lc"
 4         password = "123456"
 5         user = input("请输入账号:")
 6         pwd = input("请输入密码:")
 7         if user == username and pwd == password:
 8             func()
 9         else:
10             print("密码错误")
11     return fun

这个函数的注意点就是if后面的这个func()是login函数的参数,因为判断成功之后就要展示首页了,所以其实这里就是相当于那个shouye的函数了

 

  • 不带参数的装饰器

现在这个装饰器已经实现了,那么接下来看看怎么用

def login(func):
    def fun():
        username = "lc"
        password = "123456"
        user = input("请输入账号:")
        pwd = input("请输入密码:")
        if user == username and pwd == password:
            func()
        else:
            print("密码错误")
    return fun




@login # 调用这个装饰器
def shouye():
    print("这个是网站的首页")

这样我们其实就已经实现了一个简单的不带参数的装饰器了

  •  带参数的装饰器

那么既然说不带参数的装饰器,那肯定还存在带参数的装饰器咯

我们再来举个列子

下面有一个函数

def get():
    print("hahahaha")

 

实现的带参数的装饰器

def get_(a):
    def hun(fun):
        def func(*args, **kwargs):
            if a !=None:
                print("wo bu shi kong zhi")
                fun(*args, **kwargs)
            else:
                print("wo shi yi ge kong zhi")
                fun(*args, **kwargs)
        return func
    return hun

 

引用

@get_("hhhh")
def get():
    print("hahahaha")

由此可看出:带有参数的装饰器有三层函数嵌套,第一层为装饰器传递参数,第二层为传入被装饰对象,第三层为具体实现的扩展功能

  

  •  装饰类的装饰器

上面已经将函数的装饰器实现了,既然存在函数的装饰器,那肯定可以装饰类了,那么装饰类的装饰器怎么写呢?其实和装饰函数的装饰器差别不大

def login(func):
    def fun(*args, **kwargs):
        username = "lc"
        password = "123456"
        user = input("请输入账号:")
        pwd = input("请输入密码:")
        if user == username and pwd == password:
            return func(*args, **kwargs)   # 对比下这里与之前的有什么不同?
        else:
            print("密码错误")
    return fun
@login
class Test():
    def __init__(self):
        pass

t = Test()
print(t)

装饰类的装饰器与装饰函数的装饰器,其实大致是差不多的,只是装饰器里面的func需要return

 

 

  •  类装饰器

下面再总结下怎么创建类装饰器,何为类装饰器,也就是通过类来实现装饰器

 

首先实现类装饰器,我们要用到一个魔术方法(__call__)

那么__call__方法是干嘛的?

简单说下:__call__这个方法可以让对象变为一个可调用对象,具体可以去百度看看

举个栗子:

class C:
    def __init__(self):
        print("cccccc")


c = C()
c()

这样的话直接调用c()肯定会报错

Traceback (most recent call last):
  File "E:/KTP/test/装饰器.py", line 132, in <module>
    c()
TypeError: 'C' object is not callable

所以我们就要用到__call__方法了

class C:
    def __init__(self):
        print("cccccc")

    def __call__(self, *args, **kwargs):
        print("cccccc")


c = C()
c()

这样直接调用c()就完全没问题了

下面是实现类装饰器的代码

class B:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("这是装饰器")
        self.func(*args, **kwargs)


@B  #  print_1 = B(print1)
def print_1(num):
    print("XXXXXXXX{}".format(num))

 

这篇文章目前介绍了

1、闭包的定义

2、函数的装饰器(不带参数、带参数、通用)

3、装饰类的装饰器

4、使用类实现装饰器

 

posted @ 2020-04-03 11:55  大渝  阅读(218)  评论(0)    收藏  举报