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

原文链接: http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html
本文对原文略有改动。。。增加了自己的理解。。。
装饰器其实也就是一个函数,一个用来包装函数的函数,返回一个修改之后的函数对象,将其重新赋值原来的标识符。

1》在函数执行前和执行后分别附加其他的功能

def demo(func):#装饰函数的参数是被装饰的函数对象,返回原函数对象
    print("before myfunc() is called.")
    func()
    print("after myfunc() is called.")
    return func

def myfunc():
    print 'myfunc() is called!'

myfunc()#调用myfunc函数本身
print '------------------' 
myfunc=demo(myfunc)#该语句就是装饰的实质语句!!
print '------------------'
myfunc()#由于demo函数返回的是原函数本身,此处调用的依然是myfunc函数本身
运行结果:
myfunc() is called!
------------------
before myfunc() is called.
myfunc() is called!
after myfunc() is called.
------------------
myfunc() is called!

2》使用语法糖@来装饰函数

def demo(func):#装饰函数的参数是被装饰的函数对象,返回原函数对象
    print("before myfunc() is called.")
    func()
    print("after myfunc() is called.")
    return func
@demo  #程序运行到此处时,以myfunc为实参转去调用demo函数,将demo的返回值赋给myfunc
def myfunc():
    print 'myfunc() is called!'
print '-----------'
myfunc()#由于demo函数返回的是原函数本身,此处调用的依然是myfunc函数本身
运行结果:
before myfunc() is called.
myfunc() is called!
after myfunc() is called.
-----------
myfunc() is called!

3》使用内嵌包装函数来确保新函数被调用

def deco(func):
    def _deco():#内嵌包装函数的形参和返回值与原函数相同
        print("before myfunc() called.")
        result=func()
        print("after myfunc() called.")
        return result
    return _deco #装饰函数返回 内嵌包装函数对象
 
@deco
def myfunc():
    print("myfunc() called.")
    return 'ok'
 
print myfunc()#实际上,调用的是_demo函数
运行结果:
before myfunc() called.
myfunc() called.
after myfunc() called.
ok

4》对带参数的函数进行装饰

def deco(func):
    def _deco(a, b):#内嵌包装函数的形参和返回值与原函数相同
        print("before myfunc() called.")
        result = func(a, b)
        print("after myfunc() called.")
        return result
    return _deco#装饰函数返回内嵌包装函数对象
 
@deco
def myfunc(a,b):
    print("myfunc(%s,%s) called." % (a, b))
    return a + b
 
print myfunc(1, 2)#实际上,调用的是_demo函数
运行结果:
before myfunc() called.
myfunc(1,2) called.
after myfunc() called.
3

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

def deco(func):
    def _deco(*args, **kwargs):#参数用(*args,**kwargs),自动适应变参和命名参数
        print("before %s called." % func.__name__)
        result=func(*args, **kwargs)
        print args
        print kwargs
        print("after %s called." % func.__name__)
        return result
    return _deco
@deco
def myfunc(a,b):
    print("myfunc() called.")
    return a+b
@deco
def myfunc1(*args, **kwargs):
    print("myfunc1() called.")

print myfunc(1, 2)
print '-----------'
print myfunc1(3, 4, 5,a=1,b=2)
运行结果:
before myfunc called.
myfunc() called.
(1, 2)
{}
after myfunc called.
3
-----------
before myfunc1 called.
myfunc1() called.
(3, 4, 5)
{'a': 1, 'b': 2}
after myfunc1 called.
None
6》让装饰器带参数

def deco(arg):#和上面示例相比,在外层多了一层包装
    def _deco(func):
        def __deco():
            print("before %s called [%s]." % (func.__name__, arg))
            func()
            print("after %s called [%s]." % (func.__name__, arg))
        return __deco
    return _deco
 
@deco("mymodule")
def myfunc():
    print("myfunc() called.")
 
@deco("mymodule1")
def myfunc1():
    print("myfunc2() called.")
 
myfunc()
myfunc1()
运行结果:
before myfunc called [mymodule].
myfunc() called.
after myfunc called [mymodule].
before myfunc1 called [mymodule1].
myfunc2() called.
after myfunc1 called [mymodule1].

7》让装饰器带 类 参数

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静态方法
       因为装饰器中要调用acquire和release方法,所以类中要定义这2个方法
       之所以定义成静态方法,是因为静态方法可以通过类名来调用,不需要生成实例
    '''
    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()
运行结果:
before myfunc called [__main__.locker].
locker.acquire() called.(这是静态方法)
myfunc() called.
locker.release() called.(不需要对象实例)

8》让装饰器带函数参数

def Filter(before_func,after_func):  
    print before_func  
    print after_func  
    def outer(main_func):  
        print main_func  
        def wrapper(request,kargs):  
            before_result=before_func(request,kargs)  
            if(before_result!=None):  
                return before_result;  
  
            main_result=main_func(request,kargs)  
            if(main_result!=None):  
                return main_result;  
  
            after_result=after_func(request,kargs)  
            if(after_result!=None):  
                return after_result;  
        return wrapper  
    return outer  
  
def before(request,kargs):  
    print request,kargs,'之前!'  
  
def after(request,kargs):  
    print request,kargs,'之后!'  
 
@Filter(before,after)  
def main(request,kargs):  
    print request,kargs  
  
main('hello','python')  
print main  
运行结果:

<function before at 0x02AC7BF0>
<function after at 0x02AC7C30>
<function main at 0x02AC7CF0>
hello python 之前!
hello python
hello python 之后!
<function wrapper at 0x02AC7D30>

9》装饰器带类参数,并分拆公共类到mylocker.py文件中,同时演示了对一个函数应用多个装饰器。。。

mylocker.py文件:

#!/usr/bin/env python
#coding:utf-8
class mylocker:
    def __init__(self):
        print("mylocker.__init__() called.")   
    @staticmethod
    def acquire():
        print("mylocker.acquire() called.")    
    @staticmethod
    def unlock():
        print("mylocker.unlock() called.")

class lockerex(mylocker):
    @staticmethod
    def acquire():
        print("lockerex.acquire() called.")   
    @staticmethod
    def unlock():
        print("lockerex.unlock() called.")

def lockhelper(cls):#参数cls是 类
    '''cls必须实现acquire和unlock静态方法,静态方法可以通过类名来调用,不需要实例'''
    def _deco(func):
        def __deco(*args, **kwargs):
            print("before %s called." % func.__name__)
            cls.acquire()
            try:
                return func(*args, **kwargs)
            finally:
                cls.unlock()
        return __deco
    return _deco
decorator.py文件:

#!/usr/bin/env python
#coding:utf-8
from mylocker import *
class example:
    def __init__(self):
        print '生成一个example类的实例!!'
    @lockhelper(mylocker)
    def myfunc(self):
        print("myfunc() called.")
    @lockhelper(mylocker)
    @lockhelper(lockerex)
    def myfunc1(self, a, b):
        print("myfunc1() called.")
        return a + b
if __name__=="__main__":
    a = example()
    print a
    print '-------------'
    print a.myfunc()
    print '-------------'
    print a.myfunc1(1, 2)
运行decorator.py文件,结果:

生成一个example类的实例!!
<__main__.example instance at 0x02AA2B48>
-------------
before myfunc called.
mylocker.acquire() called.
myfunc() called.
mylocker.unlock() called.
None
-------------
before __deco called.
mylocker.acquire() called.
before myfunc1 called.
lockerex.acquire() called.
myfunc1() called.
lockerex.unlock() called.
mylocker.unlock() called.
3

如果你感觉 “对一个函数应用多个装饰器” 不容易理解,没关系,上边的例子确实有点复杂,

这儿有一个简单的例子可以帮助你理解:python 对一个函数应用多个装饰器

虽然一个函数上面可以有多个装饰器,这种情况一般不推荐使用,因为这种情况下,程序的维护比较困难。。。

(完)



  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值