• 32.Python面向对象(五)【描述符、运算符底层、装饰器:闭包-闭包参数-内置装饰器-类装饰器】


    每篇前言:


    在这里插入图片描述

    Python面向对象(五)

    1.1 描述符

    描述符协议:python描述符是一个“绑定行为”的对象属性,在描述符协议中,它可以通过方法重写属性的访问。这些方法有__get__(), __set__(), 和__delete__()
    如果这些方法中的任何一个被定义在一个对象中,这个对象就是一个描述符

    举例说明:

    # -*- coding: utf-8 -*-
    """
    __author__ = 孤寒者
    """
    # 描述符:描述符就是类里面的属性base
    # 控制实例对象a访问 这个属性 (base)  可以做一些额外的操作
    # 描述符  定义了__get__  __set__  __delete__  当中的一种
    class Base:
        def __get__(self,instance,owner):
            print('恭喜玩家获得荒古宝典')
        def __set__(self, instance,value):
            print('强化%s'%value)
        def __delete__(self,instance):
            print('武器已经损坏')
    
    class A:
        base = Base()
    
    #实例化
    a = A()
    
    a.base           # __get__        会直接输出__get__方法里面的内容
    
    a.base = 50      # __set__ 		  会直接输出__set__方法里面的内容
    
    del a.base       # __delete__	  会直接输出__delete__方法里面的内容
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

    1.2 运算符底层调用的什么?

    • +调用的是__add__

    举例说明:

    # -*- coding: utf-8 -*-
    """
    __author__ = 孤寒者
    """
    class A:
    	def __init__(self,num1,num2):
    		self.num1 = num1
    		self.num2 = num2
    
    	def __add__(self,other):      #self  实例对象   ;   other  另外一个实例对象
    		sum1 = self.num1 + other.num1
    		sum2 = self.num2 + other.num2
    		return sum1,sum2
    
    
    a = A(1,2)
    b = A(3,4)
    print(a+b)    #输出为  (4,6)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    运算符方法(了解即可)

    __add__(self,other)	# x+y
    
    • 1
    __sub__(self,other)	# x-y
    
    • 1
    __mul__(self,other)	# x*y
    
    • 1
    __mod__(self,other)	# x%y
    
    • 1
    __iadd__(self,other)	# x+=y
    
    • 1
    __isub__(self,other)	# x-=y
    
    • 1
    __radd__(self,other)	# y+x
    
    • 1
    __rsub__(self,other)	# y-x
    
    • 1
    __imul__(self,other)	# x*=y
    
    • 1
    __imod__(self,other)	# x%=y
    
    • 1

    1.3 装饰器

    有这个玩意的原因:python是一个动态语言,因为一切都是对象。是一个脚本语言。

    第一部分——引入门

    (1)首先、咱再看遍闭包是啥:

    # -*- coding: utf-8 -*-
    """
    __author__ = 孤寒者
    """
    #闭包
    def fun1():
        print('fun1')
        def fun2():
            print('fun2')
        return fun2
    
    #fun1()() ===>  fun2()
    a = fun1()
    a()           #会执行两个函数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    (2)然后,咱稍微高级点,看看闭包参数。

    这种方法比较麻烦,所以下面就引入了装饰器,和这个的功能一模一样,不过
    简单了许多:

    # -*- coding: utf-8 -*-
    """
    __author__ = 孤寒者
    """
    #闭包里面有参数        回调函数
    def aa(fun):                         #fun = f1
        print('------------aa')
        def bb():
            fun()                         #fun()   =  f1()
            print('----------bb')
        return bb
    
    def f1():
        print('this is f1')
    
    def f2():
        print('this is f2')
    
    cc = aa(f1)
    cc()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    (3)最后,就来看看第一种装饰器:

    # -*- coding: utf-8 -*-
    """
    __author__ = 孤寒者
    """
    # 装饰器   在不改变原有函数的基础上面增加额外的功能
    # 装饰器
    def aa(fun):                         #fun = f1
        print('------------aa')
        def bb():
            fun()                         #fun()   =  f1()
            print('----------bb')
        return bb
    
    # 装饰器  被装饰的函数名字(f1)会被当做参数传递给装饰函数(aa)
    # 代码就是:     aa(f1)
    # 装饰函数(aa)执行完它自己内部的代码之后,会把它的结果返回给
    # 被装饰的函数(f1)
    # 代码就是:     f1 = aa(f1)
    # 然后下面又是f1()    就相当于   aa(f1)()
    
    @aa             # 就相当于 f1 = aa(f1)   要使用嵌套函数里面的内容  aa(f1)(),就是最后调用的时候f1加个括号
                    # 而注意函数外部的只要用到装饰器就会执行,而嵌套的内层函数需要调用才会执行,所以
                    #  用处就是把重要的东西写到嵌套的内层函数,在调用的时候才会执行
    def f1():
        print('this is f1')
    
    def f2():
        print('this is f2')
    
    f1()           #输出和上面一个一模一样
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    在这里插入图片描述

    第二部分——类里面的内置装饰器

    (1)引入

    # -*- coding: utf-8 -*-
    """
    __author__ = 孤寒者
    """
    class Base:
    
        def fun(self):
            print('好好学习,天天向上')
    
    
    b = Base()
    b.fun()  # 调用类里面的方法,就会执行类里面的方法fun,打印 好好学习,天天向上
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    正题:

    (2)第一个是把类里面的方法变为属性:

    # -*- coding: utf-8 -*-
    """
    __author__ = 孤寒者
    """
    class Base:
        name = '孤寒者'
    
        @property         #将方法变为属性  更加简洁
        def fun(self):
            return('好好学习,天天向上')
    
    
    b = Base()
    print(b.name)          #属性的使用不需要加括号;方法的使用才要加括号
    print(b.fun)          #现在类里面的方法fun就变成了类的属性
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    (3)静态方法

    • 第二个是把类里面的方法变为静态方法,让其可以像使用函数一样去使用,而不需要再实例化才能使用:
    # -*- coding: utf-8 -*-
    """
    __author__ = 孤寒者
    """
    class Base:
    
        @staticmethod       #静态方法  方法能够像函数一样的去使用, 比如在类里面,你要写一些闭包什么的就可以在这里面写,相当于扩展了一些功能。
        def fun2():              # 注意:这里已经不需要self   和class类断开联系
            print('过年好,新年好')
    
        #再来个不加装饰器的
        def func(self):
            print('这是普通方法')
    
    Base.fun2()     # fun2已经变为静态方法,可以像使用函数一样的使用
    # 输出为:  过年好,新年好
    
    # Base是类名;Base() 就是实例化
    Base().func()      # 而没有使用装饰器的方法就需要先实例化,才能去使用
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    (4)第三个是类方法:

    # -*- coding: utf-8 -*-
    """
    __author__ = 孤寒者
    """
    class Base:
    
        def func(self):
            print('这是普通方法')
    
        @classmethod
        def fun3(cls):  # 没有self   和实例无关,这是类方法  ;   有self的是实例方法,需要先实例化才能使用
            print('cls类方法')
            cls().func()  # cls 代表类本身,即Base这个类
    
    
    # 类方法的使用,也不用实例化 直接类名点方法
    Base.fun3()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述

    第三部分——最后阶段

    (1)类装饰器 必须使用__call__方法

    # -*- coding: utf-8 -*-
    """
    __author__ = 孤寒者
    """
    class Base:
    
        def __init__(self,name):
            self.name = name
    
        def __call__(self,*args,**kwargs):
            print('this is call')
    
    @Base      # func = Base(func)     被装饰函数(func)当做参数传递给装饰函数(Base)
    def func():
        print('this is func')
    
    func()     # 此处的括号就相当于 func() = Base(func)()
               # __call__方法只要实例化就会被调用
    #输出为:   this is call
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    (2)看看高级点的

    # -*- coding: utf-8 -*-
    """
    __author__ = 孤寒者
    """
    class Base:
    
        def __init__(self,fun):
            self.fun = fun
    
        def __call__(self,*args,**kwargs):
            self.fun()         #就会打印    this is func
            print('this is call')
    
        def __str__(self):
            return 'this is str'
    
    @Base      # func = Base(func)  相当于实例化   被装饰函数(func)当做参数传递给装饰函数(Base)
    def func():
        print('this is func')
    
    func()     # 此处的括号就相当于 func() = Base(func)()
               # __call__方法只要实例化就会被调用
    print(func)        # 打印类的实例,就会调用类里面的__str__方法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    拓展一下呗——来个装饰器的习题

    • 测试type和isinstance两个函数,哪个速度更加的快?

    需要注意的是:程序运行速度比较快 只查看上面两个函数 运行一次的时间显示不出来效果,可以查看循环一万次的时间。

    # -*- coding: utf-8 -*-
    """
    __author__ = 孤寒者
    """
    #time.time()  计算目前的时间  时间戳(格林威治时间, 1970.1.1到现在的总秒数)
    import time
    
    def funa(fun):
        def funb():
            a = time.time()
            fun()
            b = time.time()
            print('函数运行了%s'%(b-a))
        return funb
    
    @funa
    def f1():
        for i in range(100000):
            type(1)
    f1()
    
    @funa
    def f2():
        for i in range(100000):
             isinstance(1,int)
    f2()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

  • 相关阅读:
    [附源码]计算机毕业设计基于Springboot校园订餐管理系统
    MySQL线程池
    Upload-labs十六和十七关
    使用mac自带服务器(一行命令即可启动)
    Selenium+Python系列(二) - 元素定位那些事
    Python笔记 之 闭包及装饰器
    AIGC扫盲和应用场景探究
    Transformer是如何进军点云学习领域的?
    Mac上使用Royal TSX快速连接到OCI主机
    RestSharp使用
  • 原文地址:https://blog.csdn.net/qq_44907926/article/details/126240162