写python中的装饰器
python中的装饰器主要用于在已有函数实现功能前附加需要输出的信息,下面将用实例展示我如何写装饰器。
首先分别尝试写装饰器装饰一个无参函数和一个有参函数(被装饰函数仅输出,无返回值情况下)
def my_log(func):
def wrapper():
print('decorator works')
func()
return wrapper #返回的只是wrapper函数对象,此时并没有运行 @my_log
def run(): # run=my_log(run)=wrapper 返回的是wrapper函数对象,未运行
print('run') run() #run()=wrapper() 此时调用并运行了wrapper()函数 # 运行结果如下
# decorator works
# run
def my_log(func):
def wrapper():
print('decorator works')
func()
return wrapper #返回的只是wrapper函数对象,此时并没有运行 @my_log
def add(x,y): #add=my_log(add)=wrapper 返回的也是wrapper函数对象,未运行
print(x+y) add(3,6)
#试图调用并运行wrapper() #结果出错
#TypeError: wrapper() takes 0 positional arguments but 2 were given
# 原因是运行add(3,6)时传入了两个参数add(3,6)=wrapper(3,6) 但wrapper()函数中并无参数接收
修改后的正确装饰器函数为(被装饰函数仅输出,无返回值情况下)
def my_log(func):
def wrapper(x,y):
print('decorator works')
func(x,y)
return wrapper #返回的只是wrapper函数对象,此时并没有运行 @my_log
def add(x,y): #add=my_log(add)=wrapper 返回的也是wrapper函数对象,未运行
print(x+y) add(3,6) # 运行结果如下
# decorator works
#
但并不是完善的装饰器函数(被装饰函数仅输出,无返回值情况下)
def my_log(func):
def wrapper(x,y):
print('decorator works')
func(x,y)
return wrapper #返回的只是wrapper函数对象,此时并没有运行 @my_log
def add(x,y):
print(x+y) add(3,6) @my_log
def run():
print('run') run() # 但添加无参函数run()时又出现了错误
# TypeError: wrapper() missing 2 required positional arguments: 'x' and 'y'
# 因run()=wrapper()未传给wrapper所必需的两个参数
此时需要修改装饰器中wrapper函数为非关键字可变参数和关键字可变参数来保证 无论是否有参数传入都正常运行(被装饰函数仅输出,无返回值情况下)
def my_log(func):
def wrapper(*args,**kwargs):
print('decorator works')
func(*args,**kwargs)
return wrapper #返回的只是wrapper函数对象,此时并没有运行 @my_log
def add(x,y):
print(x+y) add(3,6) @my_log
def run():
print('run') run() # 运行结果如下
# decorator works
#
# decorator works
# run
但此时装饰器函数并未完全正确(被装饰函数仅输出,无返回值情况下)
def my_log(func):
def wrapper(*args,**kwargs):
print('decorator works')
func(*args,**kwargs)
return wrapper #返回的只是wrapper函数对象,此时并没有运行 @my_log
def add(x,y):
print(x+y) @my_log
def run():
print('run') print(run.__name__)
print(add.__name__) # 运行结果如下
# wrapper
# wrapper
#因run=my_log(run)=wrapper 偷偷修改了run方法和add方法的__name__属性
需要在装饰器函数内部添加@wraps来保证被装饰函数__name__属性不被修改(被装饰函数仅输出,无返回值情况下)
from functools import wraps def my_log(func):
@wraps(func)
def wrapper(*args,**kwargs):
print('decorator works')
func(*args,**kwargs)
return wrapper #返回的只是wrapper函数对象,此时并没有运行 @my_log
def run(): # run=my_log(run)=wrapper 返回的是wrapper函数对象,未运行
print('running') run()
# run()=wrapper() print("函数run的__name__是%s"%run.__name__)
print('-'*30) @my_log # add=my_log(add)=wrapper 返回的也是wrapper函数对象
def add(a,b):
print(a+b) add(3,4)
# add(3,4)=wrapper(3,4)
print("函数add的__name__是%s"%add.__name__) # 运行结果如下
# running
# 函数run的__name__是run
# ------------------------------
# decorator works
#
# 函数add的__name__是add
被装饰函数有返回值时
from functools import wraps #***************错误*************************
def login_required(func):
@wraps(func)
def wrapper(*args,**kwargs):
print('hello world')
func(*args,**kwargs)
return wrapper @login_required
def index():
return 'aaaaaaaaaaa' a=index()
print(a)
#index=login_required()=wrapper
#index()=wrapper()
# def wrapper(*args,**kwargs):
# print('hello world')
# index() 此处只是调用index函数得到'aaaaaaaaaaa' 但wrapper函数并未返回该值 # hello world
# None 可见wrapper()调用index()函数并未返回'aaaaaaaaaaa' #**************正确********************
def login_required2(func):
@wraps(func)
def wrapper(*args,**kwargs):
print('hello world')
return func(*args,**kwargs)
return wrapper @login_required2
def index():
return 'aaaaaaaaaaa' print('-'*20)
a=index()
print(a) #输出结果如下
#--------------------
# hello world
# aaaaaaaaaaa
最后总结:
1.装饰器中定义的函数要使用*args 和**kwargs 组合来接收任何可能被装饰函数的参数,在装饰器中的wrapper函数中执行原函数时需传入*args 和**kwargs
2.需使用functools.wraps在装饰器中wrapper函数前将wrapper函数用@wraps包裹,防止被装饰函数__name__属性被修改
以下来自 CS实验室 大佬喵的 https://mp.weixin.qq.com/s?timestamp=1531273713&src=3&ver=1&signature=S-vLsC7yG6GltzbaRovEtemNFSFg3Ps*AQnH1hc3E7-huMUuZbG-i3m0c-8pkEihTO1UIA9wF4Ze8tlMKitOtFb8-eDjsQhYq7KDFDtPZpcotQikbQg8DRhzdgQHArojOFIjBhPb0wAnLzZ2hGn5PXYI4HjRy5CiEpNwr1ii09Y=
def red_oil(func):
print("ready to paint!") def red_wall_func():
print("red wall!") return red_wall_func @red_oil
def wall():
print("wall!") if __name__=="__main__":
print("start painting!!!")
执行结果如下:
ready to paint!
start painting!!!
def red_oil(func):
print("ready to paint!") def red_wall_func():
print("red wall!") return red_wall_func @red_oil
def wall():
print("wall!") if __name__=="__main__":
print("start painting!!!")
wall()
执行结果如下:
ready to paint!
start painting!!!
red wall!
装饰器在被装饰的函数被定义时立即执行,被装饰的函数在运行时才执行。
写python中的装饰器的更多相关文章
- 简单说明Python中的装饰器的用法
简单说明Python中的装饰器的用法 这篇文章主要简单说明了Python中的装饰器的用法,装饰器在Python的进阶学习中非常重要,示例代码基于Python2.x,需要的朋友可以参考下 装饰器对与 ...
- Python 中实现装饰器时使用 @functools.wraps 的理由
Python 中使用装饰器对在运行期对函数进行一些外部功能的扩展.但是在使用过程中,由于装饰器的加入导致解释器认为函数本身发生了改变,在某些情况下——比如测试时——会导致一些问题.Python 通过 ...
- python中的装饰器decorator
python中的装饰器 装饰器是为了解决以下描述的问题而产生的方法 我们在已有的函数代码的基础上,想要动态的为这个函数增加功能而又不改变原函数的代码 例如有三个函数: def f1(x): retur ...
- python中@property装饰器的使用
目录 python中@property装饰器的使用 1.引出问题 2.初步改善 3.使用@property 4.解析@property 5.总结 python中@property装饰器的使用 1.引出 ...
- 【Python】python中的装饰器——@
对装饰器本来就一知半解的,今天终于弄清楚了,Python中的装饰器是对装饰者模式的很好运用,简化到骨子里了. python中为什么需要装饰器,看这里:http://www.cnblogs.com/hu ...
- Python中的装饰器的简单介绍02
这篇博文转载自伯乐在线的12步轻松搞定python装饰器,重构成python3. 1. 函数 在python中,函数通过def关键字.函数名和可选的参数列表定义.通过return关键字返回值.我们举例 ...
- 三分钟搞定Python中的装饰器
python的装饰器是python的特色高级功能之一,言简意赅得说,其作用是在不改变其原有函数和类的定义的基础上,给他们增添新的功能. 装饰器存在的意义是什么呢?我们知道,在python中函数可以调用 ...
- 【Python】解析Python中的装饰器
python中的函数也是对象,函数可以被当作变量传递. 装饰器在python中功能非常强大,装饰器允许对原有函数行为进行扩展,而不用硬编码的方式,它提供了一种面向切面的访问方式. 装饰器 一个普通的装 ...
- 理解Python中的装饰器
文章先由stackoverflow上面的一个问题引起吧,如果使用如下的代码: @makebold @makeitalic def say(): return "Hello" 打印出 ...
随机推荐
- [浪风分享]App必死 Web永生 看Web的前世今生 必会卷土重来
当我们回顾技术的演变历史时,我们也应该关注技术演变的背后逻辑. 几年前,美国的<连线>杂志发表了“Web已死,Internet永生”的文章,由于作者之一是长尾理论的提出者克里斯.安德森(C ...
- 003android初级篇之【转】Android开发中颜色的定义方法
正好用到颜色的定义,但脑子里没有记住具体,转载一篇加强印象 1.使用Color类的常量,如: int color = Color.BLUE; // 创建一个蓝色 是使用Android提供的颜色 int ...
- javascript拼接html代码
转自开源中国社区:http://www.oschina.net/code/snippet_94055_21640经常做jsp开发的朋友可能遇到一个情况,显示列表数据不是table,而是div或者其他很 ...
- 跟上Java8 - 日期和时间实用技巧,转自知乎王爵nice
作者:王爵nice链接:https://zhuanlan.zhihu.com/p/28133858来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 当你开始使用Java操 ...
- IOS7 UI Transition Guide 状态栏 statusbar
本文转载至 http://blog.csdn.net/linzhiji/article/details/12233387 Redesign Your App for iOS 7 之 页面布局 iOS7 ...
- NOIP2011提高组(选择客栈)
题目链接:http://codevs.cn/problem/1135/ 题目大意:中文题...就不解释了 题目思路:看了其他巨巨的blog写的,dp思路 #include <iostream&g ...
- BZOJ 2431
2431: [HAOI2009]逆序对数列 Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 1521 Solved: 883[Submit][Statu ...
- .NET调用JAVA的WebService方法
调用WebService,最简单的办法当然是直接添加WEB引用,然后自动产生代理类,但是在调用JAVA的WebService时并没有这么简单,特别是对于SoapHeader的处理,在网上也有相关资料, ...
- kubectl工具的windows安装方法
1.首先安装Chocolatey 参考:https://chocolatey.org/install#install-with-powershellexe windows7+以上操作系统的cmd sh ...
- A Universally Unique IDentifier (UUID) URN Namespace
w Network Working Group P. Leach Request for Comments: 4122 Microsoft Category: Standards Track M. M ...