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
猜你喜欢
- 前言可能很多人会觉得这是一个奇葩的需求,爬虫去好好的爬数据不就行了,解析js干嘛?吃饱了撑的?搜索一下互联网上关于这个问题还真不少,但是大多
- 关于mysql数据库在Linux下的应用一直以来都是我认为比较棘手的,这次通过搭建Linux学习环境顺便研究和学习Mysql数据库在Linu
- centos下安装配置phpmyadmin,我花了二个晚上,郁闷的我不行,配置phpmyadmin简单吧,很简单,我刚工作的时候,就配置过,
- 这是一个很简单的纯CSS相册滑动浏览效果,仅用一个无序列表ul结合简单的CSS就可以实现。原文中介绍的纵向滑动相册的实现方法,但是相比之下个
- 1.建立设计规范的意义 建立设计文档的根本目的
- 阅读《YUI学习笔记(1)》YAHOO.lang.dump 与 YAHOO.lang.substitute。1.&nbs
- 凯撒密码的原理:计算并输出偏移量为3的凯撒密码的结果注意:密文是大写字母,在变换加密之前把明文字母都替换为大写字母def casar(mes
- 何为质数: 只能被1 和 自身 整除的数;方法: 利用js中求模, 看是否有余数. ---> 3%2 = 1; 5%2 = 3....
- 普通方法:爬取梨视频import reimport timeimport randomimport requestsfrom lxml im
- 随着jQuery、Mootools、prototype等知名的JavaScript框架的应用变的越来越强大,浏览器对最新版本CSS属性的支持
- PHP mysqli_stmt_init() 函数初始化声明并返回 mysqli_stmt_prepare() 使用的对象:<?php
- 对网站的LOGO设计做了一些归纳,希望得到批评,发现写的太长了,又不忍心删减,就分成两部分了,第一部分是有关设计基础的。第二部分是关于网站L
- GMSSL模块介绍GmSSL是一个开源的加密包的python实现,支持SM2/SM3/SM4等国密(国家商用密码)算法、项目采用对商业应用友
- 相信大家都做过九宫格的游戏,规则是要求填数字1-9在九个方格内,使横竖斜相加和相等。只填九个那可能有些简单,但是填25个,填49个,81个等
- 本节内容深浅拷贝循环方式字典常用方法总结一、深浅拷贝列表、元组、字典(以及其他)对于列表、元组和字典而言,进行赋值(=)、浅拷贝(copy)
- 可迭代(iterable)迭代(遍历)就是按照某种顺序逐个访问对象中的每一项。Python中有很多对象都是可以通过for语句来直接遍历的,例
- 如何显示最后十名来访者?代码和说明见下:<%Application.LockIF NOT isArray(&nbs
- 表单外观的美化很多时候,我们仅仅为了实现数据采集这个功能来使用表单,常看到的表单都是“千人一面”、毫无
- 在ASP中,你可通过VBScript和其他方式调用自程序。实例:调用使用VBScript的子程序如何从ASP调用以VBScript编写的子程
- 本文实例讲述了PHP封装CURL扩展类。分享给大家供大家参考。具体如下:<?php/*** @description: 封装CURL扩