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中的装饰器的更多相关文章

  1. 简单说明Python中的装饰器的用法

    简单说明Python中的装饰器的用法 这篇文章主要简单说明了Python中的装饰器的用法,装饰器在Python的进阶学习中非常重要,示例代码基于Python2.x,需要的朋友可以参考下   装饰器对与 ...

  2. Python 中实现装饰器时使用 @functools.wraps 的理由

    Python 中使用装饰器对在运行期对函数进行一些外部功能的扩展.但是在使用过程中,由于装饰器的加入导致解释器认为函数本身发生了改变,在某些情况下——比如测试时——会导致一些问题.Python 通过  ...

  3. python中的装饰器decorator

    python中的装饰器 装饰器是为了解决以下描述的问题而产生的方法 我们在已有的函数代码的基础上,想要动态的为这个函数增加功能而又不改变原函数的代码 例如有三个函数: def f1(x): retur ...

  4. python中@property装饰器的使用

    目录 python中@property装饰器的使用 1.引出问题 2.初步改善 3.使用@property 4.解析@property 5.总结 python中@property装饰器的使用 1.引出 ...

  5. 【Python】python中的装饰器——@

    对装饰器本来就一知半解的,今天终于弄清楚了,Python中的装饰器是对装饰者模式的很好运用,简化到骨子里了. python中为什么需要装饰器,看这里:http://www.cnblogs.com/hu ...

  6. Python中的装饰器的简单介绍02

    这篇博文转载自伯乐在线的12步轻松搞定python装饰器,重构成python3. 1. 函数 在python中,函数通过def关键字.函数名和可选的参数列表定义.通过return关键字返回值.我们举例 ...

  7. 三分钟搞定Python中的装饰器

    python的装饰器是python的特色高级功能之一,言简意赅得说,其作用是在不改变其原有函数和类的定义的基础上,给他们增添新的功能. 装饰器存在的意义是什么呢?我们知道,在python中函数可以调用 ...

  8. 【Python】解析Python中的装饰器

    python中的函数也是对象,函数可以被当作变量传递. 装饰器在python中功能非常强大,装饰器允许对原有函数行为进行扩展,而不用硬编码的方式,它提供了一种面向切面的访问方式. 装饰器 一个普通的装 ...

  9. 理解Python中的装饰器

    文章先由stackoverflow上面的一个问题引起吧,如果使用如下的代码: @makebold @makeitalic def say(): return "Hello" 打印出 ...

随机推荐

  1. AtCoder Regular Contest 070 D - No Need 想法:利用单调性二分+bitset优化

    /** 题目:D - No Need 链接:http://arc070.contest.atcoder.jp/tasks/arc070_b 题意:给出N个数,从中选出一个子集,若子集和大于等于K,则这 ...

  2. if not aa 表示如果aa等于空就是true 相当于if not aa 相当于 if aa== 空

    aa='tt' print(not aa) #表示 bb是空的 not 表示空 bb='' print(not bb)

  3. Servlet Cookie 处理

    Servlet Cookie 处理 Cookie 是存储在客户端计算机上的文本文件,并保留了各种跟踪信息.Java Servlet 显然支持 HTTP Cookie. 识别返回用户包括三个步骤: 服务 ...

  4. Hibernate标准查询语言

    Hibernate标准(Criteria)查询语言(HCQL)用于根据具体条件获取记录.Criteria接口提供了应用标准的方法,例如检索薪水大于50000的表的所有记录. HCQL的优势 HCQL提 ...

  5. 多媒体开发之音频编码---ffmpeg 编码aac

    http://blog.csdn.net/ctroll/article/details/8169396

  6. VLine[-1]=VLine[width]=128 数组的负一地址代表啥

    最近在调算法是,涉及到rgb转yuv数据的一个函数,出现了这种常见错误:如下 unsigned char *VLine = (new unsigned char[width+2]);//+1;     ...

  7. oracle ora-01652/oracle表空间

    参考: oracel bigfile tablespace:(推荐) http://blog.chinaunix.net/uid-20779720-id-3078273.html ora-01652解 ...

  8. (转载)Unity中解析ini配置文件----INIParser

    大家好,我是孙广东.   转载请注明出处:http://blog.csdn.net/u010019717 更全的内容请看我的游戏蛮牛地址:http://www.unitymanual.com/spac ...

  9. OpenCV学习笔记二十:opencv_ts模块

    一,简介: OpenCV测试库,用于单元测试.

  10. MySQL的下载及安装

    前言:不仅要知其然,还要知所以然 MySQL数据库作为关系型数据库中的佼佼者,因其体积小,速度快,成本低,不仅受到了市场的极大追捧,也受到了广大程序员的青睐.接下来,就给大家说一下,MySQL的下载和 ...