五、装饰器

一、装饰器

定义:修改其他函数功能的函数

意义:让其他函数在不修改任何代码的前提下增加其他额外的功能(比如手机壳,在不修改手机的情况下,增加手机的美观。颜色等)。不用装饰器的函数是永久性的修改,用了装饰器是函数可随时修改

举例1:

def add(a,b):
    return a + b

def new_add(add,*args,**kwargs):
    return f'<{add(*args, **kwargs)}>'

if __name__ == '__main__':
     print(f'<{add(1,1)}>')   #没有装饰器new_add时  <2>
     print(new_add(add, 1, 1))  #使用装饰器时  <2>

举例2:

def text():
    return "Hello world"

def add_itali(func):
    def wrapper():
        return f"<i>{func()}<i>"
    return wrapper

if __name__ == '__main__':
    print(add_itali(text)())  #结果: <i>Hello world<i>

使用注解符是装饰器使用更加方便:

# 先定义装饰器
def add_itali(func):
    def wrapper():
        return f"<i>{func()}<i>"
    return wrapper

#使用 @装饰器函数名 方式
@add_itali
def text():
    return "Hello world"

if __name__ == '__main__':
    print(text())  # <i>Hello world<i>

 多个装饰器时,可在函数上加多个装饰符

def add_itali(func):
    '''加粗'''
    def wrapper():
        return f"<i>{func()}<i>"
    return wrapper

def add_bold(func):
    '''倾斜'''
    def wrapper():
        return f"<b>{func()}<b>"
    return wrapper

@add_itali
@add_bold
def text():
    return "Hello world"

if __name__ == '__main__':
    print(text())  # <i><b>Hello world<b><i>

注意:调换@add_itali   @add_bold的位置,查看结果:<b><i>Hello world<i><b>

举例3:

import logging
import time

def log(func):
    def wrapper(*args, **kwargs):
        logging.info(f'{func.__name__} is running....')
        return func(*args, **kwargs)
    return wrapper

def calc_time(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        func(*args, **kwargs)
        end = time.time()
        print(f'{func.__name__} 运行了{end-start}时间')
        return func(*args, **kwargs)
    return wrapper

@log
@calc_time
def add(a,b):
    return a + b

if __name__ == '__main__':
    add(1, 3)

装饰器格式:

装饰器就是一个函数

def 装饰器名(func):
  def wrapper(*args, **kwargs):
    //要做的装饰,此处省略若干代码
    return func(*args, **kwargs)
  return wrapper

二、类的装饰器

作用:用来装饰类

def 装饰器名(cls):
    //装饰代码若干
    return cls

举例1:

def add_name(cls):
    cls.name = "zjx"
    return cls

@add_name
class A(object):
    pass

if __name__ == '__main__':
    a = A()
    print(a.name)  #结果: zjx

三、装饰器类

这个装饰器不是一个函数,而是一个类

格式如下:

class 装饰器名(object):
    def __init__(self,func):
        self.func = func
        
    def __call__(self, *args, **kwargs):
        pass # 写装饰代码
        return self.func(*args, **kwargs)

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

举例:

class A(object):
    def __init__(self,func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("call is running.....")
        result = self.func(*args, **kwargs)
        return result
@A
def add(a,b):
    return a + b

if __name__ == '__main__':
    print(add(1,3))   
''' call is running..... 4 '''

注意:调用类的对象,__call__会自动被调用

四、带参数的装饰器

如:@log(filename='text.log')

# 带参数的装饰器-三层函数(最外层用来传参)---装饰器里面可以传参数
# @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
"""

  

原文地址:https://www.cnblogs.com/zhangjx2457/p/14051827.html