首页 > 其他 > 详细

装饰器

时间:2020-04-03 13:37:43      阅读:67      评论:0      收藏:0      [点我收藏+]

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

闭包的原则:

  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 add(a, b):
    return a+b

现在增加一个需求为:需要在增加乘法、除法、减法运算

def yunsuan(fun):
    def fuc(a, b):
        print(a * b)
        print(a - b)
        print(a/b)
        fun(a, b)
    return fuc

引用

def yunsuan(fun):
    def fuc(a, b):
        print(a * b)
        print(a - b)
        print(a/b)
        fun(a, b)
    return fuc


@yunsuan
def add(a, b):
    print(a+b)

 

 

那么有没有通用的呢,比如带参数的和不带参数的我只用一个装饰器来实现呢,下面有这样一个场景:一个展示首页的和一个展示商品页面的都需要先登录,但是展示首页的函数不需要参数,展示商品页面需要传递参数

比如:

def shouye():
    print("这是首页")


def shangpin_list(num):
    print("这是商品页第{}页".format(num))

上面可以看出第一个函数是不需要参数的,第二个函数需要一个参数

我们实现登陆功能的话怎么做呢,下面请看详细操作

def login(func):
    def fun(*args, **kwargs):
        username = "lc"
        password = "123456"
        user = input("请输入账号:")
        pwd = input("请输入密码:")
        if user == username and pwd == password:
            func(*args, **kwargs)   # 注意下这里的参数前面的*不能去掉
        else:
            print("密码错误")
    return fun

好了,装饰器写好了,下面就是需要装饰函数了

def login(func):
    def fun(*args, **kwargs):
        username = "lc"
        password = "123456"
        user = input("请输入账号:")
        pwd = input("请输入密码:")
        if user == username and pwd == password:
            func(*args, **kwargs)   # 注意下这里的参数前面的*不能去掉
        else:
            print("密码错误")
    return fun

@login
def shouye():
    print("这是首页")

@login
def shangpin_list(num):
    print("这是商品页第{}页".format(num))

shouye()
print("-------------------")
shangpin_list(3)

看下打印的结果呢

请输入账号:lc
请输入密码:12345678
密码错误
-------------------
请输入账号:lc
请输入密码:123456
这是商品页第3页

很明显,我们已经实现了带参数和不带参数通用的装饰器了

 

 

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

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、使用类实现装饰器

 

装饰器

原文:https://www.cnblogs.com/LCboss/p/12508936.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!