zoukankan      html  css  js  c++  java
  • 装饰器

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

    闭包的原则:

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

  • 相关阅读:
    JavaScript 23 Window
    JavaScript 22 自定义对象
    JavaScript 21 Math
    History 7 : Christianity, Science, and The Enlightenment
    History : The Atlantic Slave Trade
    History 6 : Aztec and Inca Empires / African empires 8001500
    003 几个python编程例子
    006 网络的瓶颈效应
    0212 Logistic(逻辑)回归
    002 用Python打印九九乘法表与金字塔(*)星号
  • 原文地址:https://www.cnblogs.com/LCboss/p/12508936.html
Copyright © 2011-2022 走看看