引入:
需求:运行函数时得到该函数的名称 |
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函数,它可以让其他函数 在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值 也是一个函数对象。它经常用于有切面需求的场景, 比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。 装饰器是解决这类问题的绝佳设计,有了装饰器, 我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。 ''' def debug(func): def wrapper(): print("callner_name:" + func.__name__) return func() return wrapper @debug def say_hello(): print("hello") @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函数名称