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. Git使用技巧(2)-- 基本操作

    常用 Git 命令清单 作者: 阮一峰 编辑更新:shifu204 日期: 2016年9月 1日 我每天使用 Git ,但是很多命令记不住. 一般来说,日常使用只要记住下图6个命令,就可以了.但是熟练 ...

  2. python 面试题 string int

    str1 = 'hello' str2 = str1 str3 = str1 str4 = str1 str1 = '' int1 = 1 int2 = int1 int3 = int1 int4 = ...

  3. 瀑布流 jquery。

    本人小菜鸟一仅仅,为了自我学习和交流PHP(jquery,linux,lamp,shell,javascript,server)等一系列的知识,小菜鸟创建了一个群. 希望光临本博客的人能够进来交流. ...

  4. Android无线测试之—UiAutmator运行命令介绍与快速调试

    一.运行命令介绍: #Test.java package com.uiautomatortest; import android.os.Bundle; import android.os.Remote ...

  5. Android Studio下通过Gradle配置实现资源文件的模块化

    当开发一个app模块个数很多的时候,资源文件就会特别多,布局也会多起来,这时所有的layout都放在同一个目录下,就会显得臃肿,而且不好找相应的布局. 最近看到相关资料,发现在Android Stud ...

  6. 《从零开始学Swift》学习笔记(Day 52)——Cocoa错误处理模式

    原创文章,欢迎转载.转载请注明:关东升的博客 Swift错误处理模式,在Swift 1.x和Swift 2.0是不同的两种模式. Swift 1.x代码错误处理模式采用Cocoa框架错误处理模式,到现 ...

  7. EasyNVR智能云终端硬件使用场景分析:如何实现软硬一体的视频上云整体解决方案

    背景分析 在于众多的客户交流中,经常会被客户问到,"EasyNVR到底是软件还是硬件?"."EasyNVR能否出一个硬件的版本,摆脱自建服务器的压力?".&qu ...

  8. 用JS改变的元素CSS样式,css里display :none 隐藏 block 显示

    CSS样式的引用有3种方式:style引用.class引用.id引用,所以js改变元素的样式我们也分3种来说. 1.js改变由style方式引用的样式:方法一:document.divs.style. ...

  9. echarts之series,markLine、markPoint

    一.标记线和标志点 markLine 标记线 标记线的添加,如最大值.最小值.平均值的标记线 symbol 标记的图形. data->type 特殊的标注类型,用于标注最大值最小值等. 可选: ...

  10. 你意识到苹果公司已经抛弃了GC吗?

    为什么移动Web应用程序很慢(译) - tangzhnju - 博客园 http://www.cnblogs.com/codemood/p/3213459.html