Python中装饰器代码是怎么样的
这篇文章主要为大家展示了“Python中装饰器代码是怎么样的”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Python中装饰器代码是怎么样的”这篇文章吧。
一、理解装饰器
所有东西都是对象(函数可以当做对象传递)
由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。
def function_one(): print("测试函数")#可以将一个函数赋值给一个变量,比如foo =function_one #这里没有在使用小括号,因为我们并不是在调用function_one函数,而是在将它放在foo变量里。foo()'''测试函数Process finished with exit code 0'''
闭包的概念:
1)函数嵌套
2)内部函数使用外部函数的变量
3)外部函数的返回值为内部函数
示例:
def outer_function(message): def inner_function(): print(message) return inner_functionfunc = outer_function("你好")func() #你好
二、装饰器原型
装饰器的作用就是 不修改源代码以及原函数调用方式的情况下 给原函数增加新的功能。
#将函数作为参数传给另一个函数def decorator_function(original_function): def wrapper_function(): print('wrapper executed this before {}'.format(original_function.__name__)) original_function() return wrapper_function ''' 返回wrapper_function而不是wrapper_function();这是因为当你把一对小括号放在后面,这个函数就会执行; 然而如果你不放括号在它后面,那它可以被到处传递,并且可以赋值给别的变量而不去执行它。'''def display(): print('display function ran')decorator_display = decorator_function(display)decorator_display()
运行结果:
wrapper executed this before displaydisplay function ranProcess finished with exit code 0
1、不带参数的装饰器
def decorator_function(original_function): def wrapper_function(): print('wrapper executed this before {}'.format(original_function.__name__)) original_function() return wrapper_function@decorator_functiondef display(): #等价于display =decorator_function(display) print('display function ran')display()
运行结果:
wrapper executed this before display
display function ranProcess finished with exit code 0
2.带参数的被装饰的函数
def decorator_function(original_function): def wrapper_function(*args,**kwargs): print('wrapper executed this before {}'.format(original_function.__name__)) original_function(*args,**kwargs) return wrapper_function@decorator_functiondef display(): print('display function ran')@decorator_functiondef display_info(name,age): print('display_info ran with arguments ({},{})'.format(name,age))display()print('='*50)display_info('Michal',20)
运行结果:
wrapper executed this before display
display function ran
==================================================
wrapper executed this before display_info
display_info ran with arguments (Michal,20)Process finished with exit code 0
运行如下代码会出现一个问题
def decorator_function(original_function): def wrapper_function(*args,**kwargs): print('wrapper executed this before {}'.format(original_function.__name__)) original_function(*args,**kwargs) return wrapper_function@decorator_functiondef display(): print('display function ran')@decorator_functiondef display_info(name,age): print('display_info ran with arguments ({},{})'.format(name,age))display_info = decorator_function(display_info)print(display_info.__name__)
wrapper_function
Process finished with exit code 0
输出的应该是display_info,这里的函数被wrapper_function替代了,重写了我们函数的名字和注释文档(docstring)。Python中可以使用functools.wraps来解决这个问题。
from functools import wrapsdef decorator_function(original_function): @wraps(original_function) def wrapper_function(*args,**kwargs): print('wrapper executed this before {}'.format(original_function.__name__)) original_function(*args,**kwargs) return wrapper_function@decorator_functiondef display(): print('display function ran')@decorator_functiondef display_info(name,age): print('display_info ran with arguments ({},{})'.format(name,age))display_info = decorator_function(display_info)print(display_info.__name__)
运行结果:
display_info
Process finished with exit code 0
3.带参数的装饰器
在函数中嵌入装饰器
from functools import wrapsdef logit(logfile='out.log'): def logging_decorator(func): @wraps(func) def wrapped_function(*args, **kwargs): log_string = func.__name__ + " was called" print(log_string) # 打开logfile,并写入内容 with open(logfile, 'a') as opened_file: # 现在将日志打到指定的logfile opened_file.write(log_string + '\n') return func(*args, **kwargs) return wrapped_function return logging_decorator@logit()def myfunc1(): passmyfunc1()# Output: myfunc1 was called# 现在一个叫做 out.log 的文件出现了,里面的内容就是上面的字符串@logit(logfile='func2.log')def myfunc2(): passmyfunc2()# Output: myfunc2 was called# 现在一个叫做 func2.log 的文件出现了,里面的内容就是上面的字符串
4.使用类作为装饰器
class myDecorator(object): def __init__(self, f): print("inside myDecorator.__init__()") f() # Prove that function definition has completed def __call__(self): print("inside myDecorator.__call__()") @myDecorator def aFunction(): print("inside aFunction()") print("Finished decorating aFunction()") aFunction()
运行结果:
inside myDecorator.__init__()inside aFunction()Finished decorating aFunction()inside myDecorator.__call__()Process finished with exit code 0
被装饰后的函数aFunction()实际上已经是类myDecorator的对象。当再调用aFunction()函数时,实际上就是调用类myDecorator的对象,因此会调用到类myDecorator的__call__()方法。
因此使用类作为装饰器装饰函数来对函数添加一些额外的属性或功能时,一般会在类的__init__()方法中记录传入的函数,再在__call__()调用修饰的函数及其它额外处理。
class entryExit(object): def __init__(self, f): self.f = f def __call__(self): print("Entering", self.f.__name__) self.f() print("Exited", self.f.__name__) @entryExit def func1(): print("inside func1()") @entryExit def func2(): print("inside func2()") func1() func2()
运行结果:
Entering func1
inside func1()
Exited func1
Entering func2
inside func2()
Exited func2Process finished with exit code 0
5.使用对象作为装饰器
空参:
from functools import wrapsclass decorator_class: def __init__(self): print('执行decorator_class类的__init__()方法') def __call__(self, original_function): print('执行decorator_class类的__call__()方法') @wraps(original_function) def wrapped_function(*args, **kwargs): print('call method executed this before {}'.format(original_function.__name__)) print('执行' + original_function.__name__ + '()') original_function(*args, **kwargs) print(original_function.__name__ + '()执行完毕') return wrapped_function@decorator_class()def display_info(name,age): print('display_info ran with arguments ({},{})'.format(name,age))display_info('Michael',20)
运行结果如下:
执行decorator_class类的__init__()方法
执行decorator_class类的__call__()方法
call method executed this before display_info
执行display_info()
display_info ran with arguments (Michael,20)
display_info()执行完毕Process finished with exit code 0
带参数:
from functools import wrapsclass decorator_class: def __init__(self,arg1, arg2): print('执行decorator_class类的__init__()方法') self.arg1 =arg1 self.arg2=arg2 def __call__(self, original_function): print('执行decorator_class类的__call__()方法') @wraps(original_function) def wrapped_function(*args, **kwargs): print('执行wrapped_function()') print('call method executed this before {}'.format(original_function.__name__)) print('装饰器参数:', self.arg1, self.arg2) print('执行' + original_function.__name__ + '()') original_function(*args, **kwargs) print(original_function.__name__ + '()执行完毕') return wrapped_function@decorator_class('Hello', 'World')def display_info(name,age): print('display_info ran with arguments ({},{})'.format(name,age))display_info('Michael',20)
运行结果如下:
执行decorator_class类的__init__()方法
执行decorator_class类的__call__()方法
执行wrapped_function()
call method executed this before display_info
装饰器参数: Hello World
执行display_info()
display_info ran with arguments (Michael,20)
display_info()执行完毕Process finished with exit code 0
示例2:
from functools import wrapsclass logit(object): def __init__(self, logfile='out.log'): self.logfile = logfile def __call__(self, func): @wraps(func) def wrapped_function(*args, **kwargs): log_string = func.__name__ + " was called" print(log_string) # 打开logfile并写入 with open(self.logfile, 'a') as opened_file: # 现在将日志打到指定的文件 opened_file.write(log_string + '\n') # 现在,发送一个通知 self.notify() return func(*args, **kwargs) return wrapped_function def notify(self): # logit只打日志,不做别的 pass@logit()def myfunc1(): pass
6.多层装饰器的嵌套
#装饰器1def decorator1(func): #定义装饰之后的函数 def wrapper1(): # 装饰器1 print('1-----装饰1之前') # 调用基本函数 func() # 扩展功能2 print('1-----装饰1之后') return wrapper1#装饰器2def decorator2(func): #定义装饰之后的函数 def wrapper2(): # 装饰器2 print('2-----装饰2之前') # 调用基本函数 func() # 扩展功能2 print('2-----装饰2之后') return wrapper2#基本函数@decorator2 # 第二步:test = decorator2(eat) = test2@decorator1 # 第一步:test = decorator1(eat) = test1def test(): print('测试')#调用函数test()
运行结果:
2-----装饰2之前
1-----装饰1之前
测试
1-----装饰1之后
2-----装饰2之后Process finished with exit code 0
以上是“Python中装饰器代码是怎么样的”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网行业资讯频道!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341