Python 装饰器学习以及实际使用场景实践
前言
前几天在看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 不需要返回func
retrun _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 + b
myfunc(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 Thread
def 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_body
msg.html = html_body
send_async_email(msg)
并且这个装饰器可以适用一切需要异步处理的功能,做到非常好的代码复用。
3.5让装饰器带类参数
class locker:
def __init__(self):
print("locker.__init__() should be not called.")
@staticmethod
def acquire():
print("locker.acquire() called.(这是静态方法)")
@staticmethod
def 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 __deco
return _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
Python 装饰器学习以及实际使用场景实践的更多相关文章
- Python 装饰器学习
Python装饰器学习(九步入门) 这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 1 2 3 4 5 6 7 8 # -*- c ...
- (转载)Python装饰器学习
转载出处:http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html 这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方 ...
- Python装饰器学习
Python装饰器学习(九步入门) 这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 ? 1 2 3 4 5 6 7 8 # -*- ...
- Python 装饰器学习心得
最近打算重新开始记录自己的学习过程,于是就捡起被自己废弃了一年多的博客.这篇学习笔记主要是记录近来看的有关Python装饰器的东西. 0. 什么是装饰器? 本质上来说,装饰器其实就是一个特殊功能的函数 ...
- python 装饰器学习(decorator)
最近看到有个装饰器的例子,没看懂, #!/usr/bin/python class decorator(object): def __init__(self,f): print "initi ...
- Python装饰器学习(九步入门)
这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 ? 1 2 3 4 5 6 7 8 # -*- coding:gbk -*- '''示 ...
- python装饰器学习详解-函数部分
本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理 最近阅读<流畅的python>看见其用函数写装饰器部分写的很好,想写一些自己的读书笔记. ...
- python装饰器学习笔记
定义:本质上就是个函数,(装饰器其他函数)就是为了给其他函数添加附加功能 原则:1.不能修改被装饰的函数的源代码 2.不能修改被装饰的函数的调用方式 #-*-coding:utf-8-*- 1 imp ...
- 【转】九步学习python装饰器
本篇日志来自:http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html 纯转,只字未改.只是为了学习一下装饰器.其实现在也是没有太看明白 ...
随机推荐
- 安装好ubuntu之后要干的几件事
安装完ubuntu之后啊,系统除了自带了firefox,libre office等能用,要应付日常需求还差了些.然后我根据最近我的需求写了个清单.完成这个清单就让ubuntu成了一个得心应手的好工具了 ...
- python 求MD5值
(一)求字符串的MD5值 import hashlib #导入功能模块,此模块有MD5,SHA1,SHA256等方法 m = hashlib.md5() #声明一个对象 m.update(b'hell ...
- Android进阶练习一
1.有序广播: https://github.com/wuzhuojun/BroadcastExample 说明: 在manifest.xml设置的广播是静态注册,只要软件安装在手机上广播就能够生效. ...
- git diff 使用
1. 本地工作目录与远程仓库对比(所有改动过的文件) git diff HEAD (HEAD指向最新一次的提交,即最新版本) 2. 之对比给定的文件 git diff -- filename //是 ...
- NASM mode for Emacs
NASM mode for Emacs Quick post for those Emacs users out there. The common assembler used on GNU ...
- Window运行命令大全
1. gpedit.msc-----组策略 2. sndrec32-------录音机 3. Nslookup-------IP地址侦测器 4. explorer-------打开资源管 ...
- android fragment 跳到另一个fragment
一共有4个fragment,分别是contact(联系人),friends(朋友),search(查找),more(更多).使用的都是同一个布局,每个fragment中都有四个内部按钮,可以切换到其他 ...
- bzoj1637 [Usaco2007 Mar]Balanced Lineup
Description Farmer John 决定给他的奶牛们照一张合影,他让 N (1 ≤ N ≤ 50,000) 头奶牛站成一条直线,每头牛都有它的坐标(范围: 0..1,000,000,000 ...
- 一些.Net面试题 (BS 方向)
http://www.cnblogs.com/PurpleTide/archive/2012/03/10/2389496.html 解决方案和思路类: 设计和策略: 1.有一个网站的中购买功能, 假设 ...
- UVA 11111-Generalized Matrioshkas(栈)
题意:有很多层盒子,盒子里面再套盒子,一个盒子可能套多个独立的子盒子,但子盒子的总体积必须小于该盒子,否则不合法,输入给一行数,负数代表左边,正数代表右边,大小表示其体积,如-2,-1,1,2则表示体 ...