• 5 装饰器


    python 装饰器

    一、函数、类的数据类型

    二、装饰器

    一、函数、类的数据类型

    下面的例子,函数、类也是一种数据类型

    from types import MethodType,FunctionType
    
    class A:
        def func(self):
            pass
    
    
    def fun_test(x):
        return x
    
    
    if __name__ == '__main__':
        a = A()
        print(type(a.func))  # <class 'method'>  方法类型
        print(type(fun_test))  # <class 'function'> 函数类型
        print(isinstance(a.func, MethodType))  # True
        print(isinstance(fun_test, FunctionType))  # True

    二、装饰器

    1.什么是装饰器?

    装饰器本身也是一个函数或者类,可以新增一些被装饰函数/类的功能,简化代码。

    2.装饰器的分类:函数装饰器 、类装饰器---------(被装饰的对象可以是函数,也可以是类)

    注意:装饰器来装饰函数或者类,被装饰的函数或类的原功能是不变的,会增加一些新的功能;

               其次,被装饰的函数或者类的调用方式是不会变的

    3.装饰器的语法糖

        被装饰的函数/类名 = 装饰器名(被装饰的函数/类名)

    4.为什么要写装饰器?

    首先来看一个例子:输出结果上添加(装饰)了<>符号

    def add(a,b):
        return a + b
    
    if __name__ == '__main__':
        print(f"<{add(3,4)}>")   # <7>

    那么,如何能直接调用函数就加上<>符号,不需要手动添加呢?就是使用装饰器,对原来的函数进行装饰。

    原始装饰器的实现原理:原函数被新函数调用

    def add(a,b):
        return a + b
    
    # 原始的装饰器
    def new_add(func,*args,**kwargs):
        return f"<{func(*args,**kwargs)}>"
    
    if __name__ == '__main__':
        print(f"<{add(3,4)}>")   # <7>
        print(new_add(add,3,4))  # <7>

    原始装饰器的缺点:不够简单,需要手动传入参数

    下面写个更加简单优雅的装饰器实现原理:

    from types import FunctionType
    # 原函数
    def text():
        return "Hello Python!"
    
    
    def add_fun(func:FunctionType):
        def wrapper():
            return f"<i>{func()}</i>"
    
        return wrapper
    
    if __name__ == '__main__':
        print(add_fun(text)()) # <i>Hello Python!</i>

    加注解符号@,直接调用原函数,就可以实现对原函数的装饰。

    from types import FunctionType
    
    
    def add_fun(func:FunctionType):
        def wrapper():
            return f"<i>{func()}</i>"
    
        return wrapper
    
    @add_fun
    def text():
        return "Hello Python!"
    
    
    
    if __name__ == '__main__':
    #直接调用原函数
    print(text()) # <i>Hello Python!</i>

    装饰器的意义:团队合作开发中,一段代码被多人调用,又要增加不同的新需求,每个人都直接在原函数上作改动,是不现实的。用装饰器,既不影响原函数的调用(不修改原函数),又可以在原函数的基础增加新的功能,更加合适。

    5.一个函数被多个装饰器 装饰

    原理:从下往上

    执行:从上往下

    from types import FunctionType
    
    
    def add_fun(func: FunctionType):
        def wrapper():
            return f"<i>{func()}</i>"
    
        return wrapper
    
    
    def add_bold(func):
        def wrapper2():
            return f"<b>{func}</b>"
    
        return wrapper2
    
    
    @add_fun    # wrapper2() = add_fun() = wrapper()
    @add_bold   # text() = add_bold(text)()=wrapper2()
    def text():
        return "Hello Python!"
    
    
    if __name__ == '__main__':
        print(text())  # <i><b><function text at 0x10e0cfb00></b></i>

    6.装饰器 的应用

    1)函数装饰器---用来装饰函数

    ①实战1

    # 需求:写一个装饰器,能对任意函数进行装饰,功能:记录日志
    
    
    def log(func):
        def wrapper(*args, **kwargs):
            print(f"{func.__name__}函数正在运行...")
            return func(*args, **kwargs)
        return wrapper
    
    @log
    def add(a, b):
        return a + b
    
    if __name__ == '__main__':
        print(add(1,2))
    """
    add函数正在运行...
    3
    """

    ②计算函数的运行时间

    # 计算函数运行的时间
    
    import time
    
    
    def caculate_time(func):
        def wrapper(*args, **kwargs):
            start_time = time.time()
            result = func(*args, **kwargs)
            time.sleep(0.5)
            end_time = time.time()
            return end_time - start_time
    
        return wrapper
    
    
    @caculate_time
    def add(a, b):
        return a + b
    
    
    if __name__ == '__main__':
        print(add(3, 4))  # 0.5043981075286865

    2)类的装饰器---用来装饰类

    # 类的装饰器
    """
    格式
    def 装饰器名(cls):
        装饰代码
        return cls
    
    """
    name = "python"
    
    def add_name(cls):
        cls.name = name
        return cls
    
    @add_name
    class A(object):
        pass
    
    if __name__ == '__main__':
        a = A()
        print(a.name)

    3)装饰器类

    _ _call_ _方法:函数的调用,实际就是调用函数里的_ _call_ _方法

    # 这个装饰器是一个类(不是函数)
    """
    格式
    class 装饰器名(object):
        def __init__(self,func):
            pass
        def __call__(self,*args,**kwargs):   # 调用类的对象时,call会被自动调用执行
            装饰代码段
            return self.func(*args,**kwargs)
    
    """
    
    class A(object):
        def __init__(self,func):
            self.func = func
    
        def __call__(self, *args, **kwargs):
            print(f"{self.func.__name__}函数正在被调用...")
            result = self.func(*args, **kwargs)
            return result
    
    @A
    def add(a, b):
        return a + b
    
    if __name__ == '__main__':
        print(add(1,2))

    4)带参数的装饰器

    # 带参数的装饰器-三层函数(最外层用来传参)---装饰器里面可以传参数
    # @log(filename = "123.txt")
    
    import logging
    
    def add_log(filename):       # 最外层:接收装饰参数
        def inner(func):         # 中间层:接收被装饰函数
            def wrapper(*args, **kwargs):  # 内层装饰函数:接收被装饰的函数的参数
                logging.warning(f"{func.__name__}函数正在被调用...")
                result = func(*args, **kwargs)  # 调用被装饰函数
                return result
            return wrapper
        return inner
    
    
    @add_log(filename="123.txt")
    def add(a, b):
        return a + b
    
    if __name__ == '__main__':
        print(add(3,4))
    """
    WARNING:root:add函数正在被调用...
    7
    """
  • 相关阅读:
    Android学习笔记37-使用Content Providers方式共享数据
    Android学习笔记36-使用SQLite方式存储数据
    Android学习笔记35-使用Shared Preferences方式存储数据
    Android学习笔记34-使用文件存储数据
    Android学习笔记33-Intent介绍及Intent在Activity中的使用方法
    Android学习笔记32-滑屏控件ViewPager的使用
    Android学习笔记31-使用惰性控件ViewStub实现布局动态加载
    Android学习笔记30-列表ListView控件的使用
    Android学习笔记29-切换卡TabHost控件的使用
    用户代理
  • 原文地址:https://www.cnblogs.com/ananmy/p/14062262.html
Copyright © 2020-2023  润新知