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. IOS设计模式浅析之桥接模式(Bridge)

    引言 在项目开发中,我们会遇到这样的一种场景:某些类型由于自身的逻辑,往往具有两个或多个维度的变化,比如说大话设计模式书中所说的手机,它有两个变化的维度:一是手机的品牌,可能有三星.苹果等:二是手机上 ...

  2. 学习百度、腾讯及lofter的前端兼容及布局

  3. python cookies 爬虫处理

    Cookie Cookie 是指某些网站服务器为了辨别用户身份和进行Session跟踪,而储存在用户浏览器上的文本文件,Cookie可以保持登录信息到用户下次与服务器的会话. Cookie原理 HTT ...

  4. ios -WKWebView 高度 准确,留有空白的解决方案

    #import "ViewController.h" #import <WebKit/WebKit.h> @interface ViewController ()< ...

  5. 正则表达式初识,re模块

    作业收藏 # 3.reversed和sorted和list列表类型内置的sort.reverse有什么区别? #reversed 的返回值是一个迭代器并不会直接修改原列表 sorted的返回值是生成一 ...

  6. linux下的shell 快捷键

    Ctrl+p重复上一次命令Ctrl+a跳到第一个字符前Ctrl+x同上但再按一次会从新回到原位置Ctrl+b前移一个字符不删除字符情况下Ctrl+h删除前一个字符Ctrl+u删除提示符前的所有字符Ct ...

  7. 在看lua仿单继承

    --lua仿单继承 Account = { balance = } --对于成员变量,第一此访问要使用元表中的,在第一次也赋值到自己的域中了 --将不涉及到__index了 function Acco ...

  8. 自然语言处理(NLP)资源

    1.HMM学习最佳范例全文文档,百度网盘链接: http://pan.baidu.com/s/1pJoMA2B 密码: f7az 2.无约束最优化全文文档 -by @朱鉴 ,百度网盘链接:链接:htt ...

  9. 32位Win7下安装与配置PHP环境(一)

    运行PHP网站,主要需要安装.配置三个软件,Apache.PHP和MySQL.如果需要编辑调试PHP程序,还要安装一个编辑调试软件. 一. Apache Apache是和IIS类似的一个软件,是运行在 ...

  10. 单片机c语言教程:C51循环语句

    单片机c语言教程第十三课 C51循环语句 循环语句是几乎每个程序都会用到的,它的作用就是用来实现需要反复进行多次的操 作.如一个 12M 的 51 芯片应用电路中要求实现 1 毫秒的延时,那么就要执行 ...