前言

前几天在看Flask框架,对于非常神奇的@语法,不是非常的理解,回来补装饰器的功课。阅读很多的关于装饰器的文章,自己整理一下,适合自己的思路的方法和例子,与大家分享。

app = Flask(__name__)@app.route("/")
def hello():return "Hello World!"

1、装饰器是什么

装饰器是Python语言中的高级语法。主要的功能是对一个函数、方法、或者类进行加工,作用是为已经存在的对象添加额外的功能,提升代码的可读性。
装饰器是设计模式的一种,被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等

2、装饰器的语法

装饰器的语法如下:

当前Python的装饰器语法如下:
@dec2
@dec1
def func(arg1, arg2, ...):....return funx上面的代码相当于:def func(arg1, arg2, ...):pass
func = dec2(dec1(func))

装饰器可以用def的形式来定义。装饰器接收一个可调用对象作为输入参数,并返回一个新的可调用对象。
装饰器新建了一个可调用对象,也就是return 返回的函数funx,在新增的函数中,可以添加我们需要的功能,并通过调用原有函数来实现原有函数的功能。

3、装饰器的使用

3.1不带参数的装饰器

定义装饰器非常的简单:

def deco(func):"""无参数调用decorator声明时必须有一个参数,这个参数将接收要装饰的方法"""print "before myfunc() called."func()print "after myfunc() called."return func@deco
def myfunc():print " myfunc() called."myfunc()
myfunc()

定义好装饰器后,就可以通过@语法来使用了,在函数的定义前调用@+装饰器函数名,即可使用。上面这个装饰器在使用的时候有一个问题,即只在第一次被调用,并且原来的函数多执行一次。执行输出如下:

before myfunc() called.  myfunc() called.after myfunc() called.myfunc() called.   --函数多执行一次的输出myfunc() called.   --第二次调用,装饰器不生效

要保证新函数每次被调用,使用下面的方法来定义装饰器

def deco(func):"""无参数调用decorator声明时必须有一个参数,这个参数将接收要装饰的方法"""def _deco():print "before myfunc() called."func()print "after myfunc() called."#return func 不需要返回funcretrun _deco
@deco
def myfunc():print " myfunc() called."return 'OK'myfunc()
myfunc()

函数输出如下:

before myfunc() called.myfunc() called.after myfunc() called.
before myfunc() called.myfunc() called.after myfunc() called.

这样可以看到,装饰器每次都得到了调用。

3.2带参数的函数进行装饰器

def deco(func):def _deco(a, b):print("before myfunc() called.")ret = func(a, b)print("  after myfunc() called. result: %s" % ret)return ret
return _deco@deco
def myfunc(a, b):print(" myfunc(%s,%s) called." % (a, b))return a + bmyfunc(1, 2)
myfunc(3, 4)

输出:
before myfunc() called.
myfunc() called.
After myfunc() called. result: 3

before myfunc() called.
myfunc() called.
After myfunc() called. result: 7

内嵌函数的形参和返回值与原函数相同,装饰函数返回内嵌包装函数。

3.3装饰器带参数

def decoWithArgs(arg):
"""由于有参数的decorator函数在调用时只会使用应用时的参数而不接收被装饰的函数做为参数,所以必须返回一个decorator函数, 由它对被装饰的函数进行封装处理"""
def newDeco(func):    #定义一个新的decorator函数def replaceFunc():    #在decorator函数里面再定义一个内嵌函数,由它封装具体的操作print "Enter decorator %s" %arg    #进行额外操作return func()    #对被装饰函数进行调用return replaceFunc
return newDeco    #返回一个新的decorator函数@decoWithArgs("demo")
def MyFunc():    #应用@decoWithArgs修饰的方法print "Enter MyFunc"MyFunc()    #调用被装饰的函数

输出:
nter decorator demo
Enter MyFunc

这个情形适用于原来的函数没有参数,新增加打印的情况。常见适用的地方是增加函数的打印日志。

3.4对参数数量不确定的函数进行装饰

下面的例子是一个邮件异步发送的例子,函数的参数数据部确定,装饰器实现了对于邮件发送函数的异步发送。

from threading import Threaddef async(f):def wrapper(*args, **kwargs):thr = Thread(target = f, args = args, kwargs = kwargs)thr.start()return wrapper@async
def send_async_email(msg):mail.send(msg)def send_email(subject, sender, recipients, text_body, html_body):msg = Message(subject, sender = sender, recipients = recipients)msg.body = text_bodymsg.html = html_bodysend_async_email(msg)

并且这个装饰器可以适用一切需要异步处理的功能,做到非常好的代码复用。

3.5让装饰器带类参数

class locker:def __init__(self):print("locker.__init__() should be not called.")@staticmethoddef acquire():print("locker.acquire() called.(这是静态方法)")@staticmethoddef release():print("  locker.release() called.(不需要对象实例)")def deco(cls):'''cls 必须实现acquire和release静态方法'''def _deco(func):def __deco():print("before %s called [%s]." % (func.__name__, cls))cls.acquire()try:return func()finally:cls.release()return __decoreturn _deco@deco(locker)
def myfunc():print(" myfunc() called.")myfunc()
myfunc()

输出为:

before myfunc called [__main__.locker].
locker.acquire() called.(this is staticmethon)
myfunc() called.locker.release() called.(do't need object )before myfunc called [__main__.locker].
locker.acquire() called.(this is staticmethon)
myfunc() called.locker.release() called.(do't need object )

装饰器总结

当我们对某个方法应用了装饰方法后, 其实就改变了被装饰函数名称所引用的函数代码块入口点,使其重新指向了由装饰方法所返回的函数入口点。由此我们可以用decorator改变某个原有函数的功能,添加各种操作,或者完全改变原有实现。

参考文章

感谢以下几位大神:

http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html

http://www.cnblogs.com/Jifangliang/archive/2008/07/22/1248313.html

http://www.cnblogs.com/vamei/archive/2013/02/16/2820212.html

转载于:https://www.cnblogs.com/StitchSun/p/4600835.html

Python 装饰器学习以及实际使用场景实践相关推荐

  1. Python装饰器学习(九步入门)

    这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 1 2 3 4 5 6 7 8 # -*- coding:gbk -*- '''示例1 ...

  2. Python装饰器学习笔记

    Python装饰器 文章目录 Python装饰器 基本概念 从零开始的逐步分析 修饰后的问题 向被包装后的函数传递参数 使用场景:stdout日志 接受参数的装饰器 作为一个类的装饰器 总结 学习资料 ...

  3. Python装饰器学习笔记 1

    前言 最近跟着<流畅的Python>和<Python Cookbook>学习,看到装饰器部分,有些头大 倒不是因为概念难以理解,而是书和网上文章中有些地方有些矛盾之处 在简单学 ...

  4. Python装饰器学习记录.

    装饰器 Python函数基础 python中万物皆对象,看一个实例: ​这里需要注意,单纯地函数名和函数名加括号是两种概念,前者表示该函数定义本身,而后者表示函数执行,实际上是函数的执行结果. 函数中 ...

  5. python装饰器学习

    装饰器 要学会装饰器,必须首先知道什么是闭包. 闭包: 在函数中提出的概念 就是内层函数对外层函数(非全局变量的运用)并且返回值是内部函数的引用. 格式: - def 外部函数:def内部函数:ret ...

  6. python 函数装饰器学习

    如果看<Python 核心编程>上的讲解还是不太清楚,我建议看这个链接: Python装饰器学习 看完之后,这里有一些总结: 其实总体说起来,装饰器其实也就是一个**函数**,一个用来** ...

  7. Python 装饰器 函数

    Python装饰器学习(九步入门):http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html 浅谈Python装饰器:https://b ...

  8. Python装饰器详解,详细介绍它的应用场景

    装饰器的应用场景 附加功能 数据的清理或添加: 函数参数类型验证 @require_ints 类似请求前拦截 数据格式转换 将函数返回字典改为 JSON/YAML 类似响应后篡改 为函数提供额外的数据 ...

  9. 一篇文章汇总Python装饰器全知识图谱(使用场景,基本用法,参数传递,闭包操作,类装饰器和AOP)

    装饰器,是将Python代码变得低耦合,简洁优美的必经之路,同时也是实现闭包操作,AOP编程的基础.这一篇博客从装饰器的产生原因,基本使用,延伸到参数传递,闭包操作,最后到类装饰器和AOP,希望能用我 ...

最新文章

  1. php 许愿墙 阶段案例_房地产全周期设计管控流程解析及跨部门合作及案例分析...
  2. python可以做什么有趣的东西-您用python做过什么有趣的事?(什么事python)
  3. 1305. GT考试
  4. SpringCloud Zuul(六)之PRE Filter
  5. IoT SaaS加速器——助力阿尔茨海默病人护理
  6. IDEA Maven项目左边栏只能看到pom文件
  7. OPENWRT传感器实验
  8. AIX下sort命令简介及使用
  9. android 工厂测试内存,Android性能测试之内存
  10. 允许其他网络用户通过此计算机的internet连接来连_「Azure云」什么是Azure虚拟网络?...
  11. 帧传送、关联与身份验证状态
  12. iOS 面试题分析(二)
  13. recipe terminated with fatal error: spawn xelatex enoent.
  14. 将一个网页设置为屏保
  15. 认识计算机键盘ppt教案,认识计算机键盘.ppt
  16. 第七章--图--基本概念
  17. 好用的GraphViz 在线绘图收集
  18. 嵌入式工程师不能不参加的技术盛会
  19. VMware 虚拟器安装kali镜像
  20. O2O商城系统,适合本地电商发展的商城系统!

热门文章

  1. python选择题题库for、if_Python题目1:猜年龄(for、if else和where)
  2. 贵州大学计算机科学研究所,贵州大学计算机科学与技术学院
  3. v8声卡调音软件_sE VOXTOON AF2评测:解决复杂跳线需求的声卡
  4. es6 filter方法_ES5和ES6函数你不知道的区别
  5. python generator输出_python 高级特性:Generator(生成器)
  6. vba 自动换行_Excel中quot;强制换行quot;quot;快速求和quot;等操作,这9个AlT键技巧全都包含了...
  7. 2013江苏计算机二级vfp试题,2013年计算机二级VFP上机试题及答案解析51
  8. 2×3卡方检验prism_分类变量的相关性:五分钟掌握卡方检验「从理论到Python实战」...
  9. mysql 范围优化_如何优化mysql的范围查询
  10. xp系统没有服务器时间,WinXP系统时间无法同步网络时间连时区也不显示的解决方法...