Python装饰器代码详解
作者:凡晨丹心 发布时间:2021-04-28 23:16:03
一、理解装饰器
所有东西都是对象(函数可以当做对象传递)
由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。
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_function
func = 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 display
display function ran
Process 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_function
def 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_function
def display():
print('display function ran')
@decorator_function
def 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_function
def display():
print('display function ran')
@decorator_function
def 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 wraps
def 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_function
def display():
print('display function ran')
@decorator_function
def 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 wraps
def 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():
pass
myfunc1()
# Output: myfunc1 was called
# 现在一个叫做 out.log 的文件出现了,里面的内容就是上面的字符串
@logit(logfile='func2.log')
def myfunc2():
pass
myfunc2()
# 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 wraps
class 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 wraps
class 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 wraps
class 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.多层装饰器的嵌套
#装饰器1
def decorator1(func):
#定义装饰之后的函数
def wrapper1():
# 装饰器1
print('1-----装饰1之前')
# 调用基本函数
func()
# 扩展功能2
print('1-----装饰1之后')
return wrapper1
#装饰器2
def decorator2(func):
#定义装饰之后的函数
def wrapper2():
# 装饰器2
print('2-----装饰2之前')
# 调用基本函数
func()
# 扩展功能2
print('2-----装饰2之后')
return wrapper2
#基本函数
@decorator2 # 第二步:test = decorator2(eat) = test2
@decorator1 # 第一步:test = decorator1(eat) = test1
def test():
print('测试')
#调用函数
test()
运行结果:
2-----装饰2之前
1-----装饰1之前
测试
1-----装饰1之后
2-----装饰2之后Process finished with exit code 0
来源:https://blog.csdn.net/Michaelyq1229/article/details/120941215


猜你喜欢
- 首先声明:本人虽然在web前端岗位干了好多年,但无奈岗位对技术要求不高。html,css用的比较多,JavaScript自己原创的很少,基本
- 侧边栏在响应式设计中起到很大的作用,当屏幕小到手机的屏幕时,能够自适应屏幕大小的侧边栏固然能够为网站添加色彩,那么在Bootstrap的框架
- 这篇文章主要介绍的是关于JS的命名规范、注释规范以及框架开发的一些问题,首先来看看目录。目录1. 命名规范:介绍变量、函数、常量、构造函数、
- 对于刚刚学习编程的同学来说对编程是非常陌生的,对很多的代码也是非常陌生,高中忙于学习的我们甚至可以说是对编程是一无所知,进入大学进入到这个专
- append(),extend(), insert()都是列表操作中常用的插入函数。其中前两个均接收一个参数,并插入到列表尾部。最后一个接收
- 前言众所周知,网页版的B站无法下载视频,然本人喜欢经常在B站学习,奈何没有网时,无法观看视频资源,手机下载后屏幕太小又不想看,遂写此程序以解
- 我们都知道,可以使用高德地图api实现经纬度与地址的转换。那么,当我们有很多个地址与经纬度,需要批量转换的时候,应该怎么办呢?在这里,选用高
- 在Goland中,如果 import 了包,但在代码中没有使用,会自动帮你移除这个包的 引用有可能是习惯问题,每次写代码都习惯 先impor
- JSP 获取spring容器中bean的方法总结方案1(Web中使用):ApplicationContext ct = WebApplica
- 使用程序难免会有出错的时候,如何从大篇代码中找出错误,不仅考验能力,还要考验小伙们的耐心。辛辛苦苦敲出的代码运行不出结果,非常着急是可以理解
- Server对象提供对服务器上访问的方法和属性.大多数方法和属性是作为实用程序的功能提供的。语法:Server.property|metho
- 本文实例讲述了Python高级编程之消息队列(Queue)与进程池(Pool)。分享给大家供大家参考,具体如下:Queue消息队列1.创建i
- 一篇关于STR和UNICODE的好文章整理下python编码相关的内容注意: 以下讨论为Python2.x版本, Py3k的待尝试开始用py
- 一、继承与java的继承不同python支持多继承,如Person类同时继承Animal类和Species类可以这样写:class Anim
- 变量的种类在T-SQL中,变量按生存范围可以分为全局变量(Global Variable)和局部变量(Local Variable)全局变量
- 前言如果一个类是别人编写的,又没有帮助文档,怎么样来查看所有成员函数呢?本文详细给大家介绍了关于python用dir函数查看类中所有成员函数
- 如果需要一个简单的Web Server,而不是安装那些复杂的HTTP服务程序,比如:Apache,Nginx等。那么可以使用Python自带
- 如下所示:#python解决字符串倒序输出def string_reverse(m): num=len(m) a=[] for i in r
- 传说用这个语句管用:select top 5 * from tablename order by newid() 我放到sql的查询分析器里
- 一、使用selenium前?1.安装seleniumpip install Selenium2.安装浏览器驱动Chrome驱动文件下载:点击