Python核心编程之装饰器

引入:

需求:运行函数时得到该函数的名称
版本一:直接print函数名称
缺陷:当函数名称发生改变时,print中的内容也需要改变。硬编码
import inspect
'''
转载:https://www.cnblogs.com/cicaday/p/python-decorator.html
需求:运行函数时得到该函数的名称
版本一:直接print函数名称
缺陷:当函数名称发生改变时,print中的内容也需要改变。硬编码
'''
def say_hello(): print("hello") def say_goodbye(): print("goodbye") if __name__ == "__main__": say_hello() say_goodbye()
版本二:调用inspect模块中的stack()方法,获取函数名称
缺陷:调用debug()方法多次
import inspect
'''
需求:运行函数时得到该函数的名称
版本二:调用inspect模块中的stack()方法,获取函数名称
缺陷:调用debug()方法多次
'''
def debug():
    caller_name = inspect.stack()
    print("caller_name: " + caller_name[1][3])

def say_hello():
    debug()
    print("hello")
def say_goodbye():
    debug()
    print("goodbye")

if __name__ == "__main__":
    say_hello()
    say_goodbye()

装饰器:

版本三:装饰器
---------装饰器:装饰器的作用就是为已经存在的函数或对象添加额外的功能。
    装饰器本质上是一个Python函数,它可以让其他函数
    在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值
    也是一个函数对象。它经常用于有切面需求的场景,
    比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。
    装饰器是解决这类问题的绝佳设计,有了装饰器,
    我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
'''

一、不带参数的装饰器

import inspect
'''
需求:运行函数时得到该函数的名称
版本四:装饰器
---------装饰器:装饰器的作用就是为已经存在的函数或对象添加额外的功能。
    装饰器本质上是一个Python函数,它可以让其他函数
    在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值
    也是一个函数对象。它经常用于有切面需求的场景,
    比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。
    装饰器是解决这类问题的绝佳设计,有了装饰器,
    我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
@log
def a():
  pass
@log语法糖知识告诉python解释器插入代码:a = log(a)
'''
def debug(func):
    def wrapper():
        print("callner_name:" + func.__name__)
        return func()
    return wrapper

# say_hello = debug(say_hello) = wrapper @debug
def say_hello(): print("hello")
# say_goodbye = debug(say_goodbye) = wrapper @debug
def say_goodbye(): print("goodbye") if __name__ == "__main__": say_hello() print('say_hello()实际调用的函数:'+ say_hello.__name__) say_goodbye() print('say_goodbye()实际调用的函数:'+ say_goodbye.__name__)
'''运行结果
callner_name:say_hello
hello
say_hello()实际调用的函数:wrapper
callner_name:say_goodbye
goodbye
say_goodbye()实际调用的函数:wrapper
'''

二、带参数的装饰器

import inspect
'''
装饰器传参数
理解*args, **kwargs: splat运算符* **
*args: 将传入的位置参数打包成元组(可变参数)
**kwargs: 将传入的关键字参数打包成字典(可选参数)

到这里已经掌握了初级装饰器的写法
'''
def add_sum(*args):
    print(args)
    print(type(args))

def add_s(**kwargs):
    print(kwargs)
    print(type(kwargs))
    for key, value in kwargs.items():
        print(f"{key}:{value}")

def debug(func):
    def wrapper(*args, **kwargs):  # 宇宙无敌参数
        print("callner_name:" + func.__name__)
        return func(*args, **kwargs)
    return wrapper
@debug
def say_hello(somthing):
    print(f"hello{somthing}")

@debug
def say_goodbye(something):
    print(f"goodbye{something}")


if __name__ == "__main__":
    add_sum(1, 2, 3, 4, 5)
    add_s(a=1, b=2, c=3)
    print(*[1, 2, 3, 4])
    print(*{'a': 1, 'b': 2, 'c': 3})
    say_hello('!')
    say_goodbye('!')
'''运行结果
(1, 2, 3, 4, 5)
<class 'tuple'>
{'a': 1, 'b': 2, 'c': 3}
<class 'dict'>
a:1
b:2
c:3
1 2 3 4
a b c
callner_name:say_hello
hello!
callner_name:say_goodbye
goodbye!
'''

三、不带参数的类装饰器

import inspect
'''
基于类实现的装饰器(不带参数):callable 可以调用
    装饰器函数其实是这样一个接口约束,
它必须接受一个callable对象作为参数,
然后返回一个callable对象。
在Python中一般callable对象都是函数,
但也有例外。只要某个对象重载了__call__()方法,
那么这个对象就是callable的。
'''
class Test():
    def __call__(self, *args, **kwargs):
        print('call me')

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

    # 内置方法
    def __call__(self, *args, **kwargs):
        print("[DEBUG]: enter function {func}()".format(
            func=self.func.__name__))
        return self.func(*args, **kwargs)
@logging
def say(something='Toney'):
    print("say {}!".format(something))

# say = logging(say)
# say(something='Toney')  --> 执行内置方法
if __name__ == "__main__":
   t = Test()
   t()
   say()
'''运行结果
call me
[DEBUG]: enter function say()
say Toney!
'''
 

四、带参数的类装饰器

import inspect
'''
带参数的类装饰器
'''
class logging(object):
    def __init__(self, level):
        self.level = level

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print("[DEBUG]: enter function {level}()".format(
                level=self.level))
            func(*args, **kwargs)
        return wrapper
@logging(level = 'INFO')
def say(something='Toney'):
    print("say {}!".format(something))
# say = logging(level = 'INFO')
# say = say(something='Toney') --> say = wrapper
if __name__ == "__main__":
   say()
'''运行结果
[DEBUG]: enter function INFO()
say Toney!
'''

需求:运行函数时得到该函数的名称
版本一:直接print函数名称
原文地址:https://www.cnblogs.com/854594834-YT/p/13795614.html