python~装饰器详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_37579123/article/details/85268440

装饰器的概念

在代码运行期间在不改变原函数定义的基础上,动态给该函数增加功能的方式, 称之为装饰器。

装饰器是一个很著名的设计模式,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

总体来说,装饰器其实也是一个函数,一个用来包装函数的函数,返回一个修改之后的函数对象,将其重新赋值给原来的标识符,并永久丧失对原始函数对象的访问。

装饰器的本质:一个闭包函数

装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展

装饰器应用示例:使用@将装饰器应用到函数

import time

def now():
    print ("current time is %s" % time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()))

def log(func):
    def wrapper(*args,**kw):
        print ("call %s" % func.__name__)
        return func(*args,**kw)
    return wrapper

#now()
#print (type(log(now)))
log(now)()
========================================================================================

#使用@将装饰器应用到函数
import time

def log(func):
    “定义装饰器”
    def wrapper(*args,**kw):
        print ("call %s" % func.__name__)
        return func(*args,**kw)
    return wrapper

@log
def now():
    print ("current time is %s" % time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()))

now()   #等同于不加@时的log(now)()调用

#使用闭包和使用装饰器后的运行结果是一样的

装饰器分类

装饰器分为无参数decorator和有参数decorator

无参数decorator:生成一个新的装饰器函数

有参数decorator:装饰函数先处理参数,再生成一个新的装饰器函数,然后对函数进行装饰

装饰器的具体定义:

1、把要装饰的方法作为输入参数;

2、在函数体内可以进行任意的操作(可以想象其中会有很多应用场景);

3、只要确保最后返回一个可执行的函数即可(可以是原来的输入参数函数,也可以是一个新函数)

装饰器学习九步法—第一步

最简单的函数,准备附加额外功能

代码示例:

def myfunc():
    print ("myfunc() called!")

myfunc()
myfunc()

装饰器学习九步法—第二步

使用装饰函数在函数执行前和执行后分别附加额外功能

代码示例:

#装饰函数的参数是被装饰的函数对象,返回原函数对象
#装饰的实质语句:myfunc=deco(myfunc)

def deco(func):
    print ("before myfunc() called!")
    func()
    print ("after myfunc() called!")
    return func

def myfunc():
    print ("myfunc() called!")

deco(myfunc)
print ("*"*10)
myfunc=deco(myfunc)   
print ("*"*10)
myfunc()
myfunc()

装饰器学习九步法—第三步

使用语法糖@来装饰函数,相当于“myfunc = deco(myfunc)” 但发现新函数只在第一次被调用,且原函数多调用了一次

代码示例:

def deco(func):
    print ("before myfunc() called!")
    func()
    print ("after myfunc() called!")
    return func

@deco
def myfunc():
    print ("myfunc() called!")

myfunc()
print ("*"*10)
myfunc()

装饰器学习九步法—第四步

使用内嵌包装函数来确保每次新函数都被调用

代码示例:

def deco(func):
    def _deco():
        print ("before myfunc() called!")
        func()
        print ("after myfunc() called!")
    return _deco


@deco               #等价于不带@时,myfunc=deco(myfunc)
def myfunc():
    print ("myfunc() called!")

print (myfunc.__closure__)
myfunc()
print ("*"*10)
myfunc()

装饰器学习九步法—第五步

对带参数的函数进行装饰

def deco(func):
    def _deco(a,b):
        print ("before myfunc() called!")
        func(a,b)
        print ("after myfunc() called!")
    return _deco

@deco               #等价于不带@,myfunc=deco(myfunc)
def myfunc(a,b):
    print ("myfunc() called!",a*b)

#print (myfunc.__closure__)
myfunc(1,2)
print ("*"*10)
myfunc(2,3)

装饰器学习九步法—第六步

对参数数量不确定的函数进行装饰,参数用(*args, **kwargs),自动适应变参和命名参数

def deco(func):
    def _deco(*args,**kwargs):
        print ("before myfunc() called!")
        func(*args,**kwargs)
        print ("after myfunc() called!")
    return _deco

@deco               #等价于不带@,myfunc=deco(myfunc)
def myfunc(*args,**kwargs):
    print ("myfunc() called!",(*args))
    for key,value in kwargs.items():
        print (key,value)

#print (myfunc.__closure__)
myfunc(1,2,word1=1)
print ("*"*10)
myfunc(2,3,word2=2)

装饰器学习九步法—第七步

在示例4的基础上,让装饰器带参数, 和上一示例相比在外层多了一层包装。 装饰函数名实际上应更有意义些。

代码示例:

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("23")    #语法糖的作用等价于myfunc=deco("23")(myfunc)
def myfunc():
    print ("myfunc() called!")

#myfunc=deco("23")(myfunc)
myfunc()
========================================================================
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")    #语法糖的作用等价于myfunc=deco("mymodule")(myfunc)
def myfunc():
    print ("myfunc() called!")

@deco("yourmodule")    #语法糖的作用等价于myfunc2=deco("yourmodule")(myfunc)
def myfunc2():
    print ("myfunc() called!")

myfunc()
print ("*"*20)
myfunc2()

装饰器学习九步法—第八步

让装饰器带类参数

代码示例:

#encoding:utf-8

class Locker(object):
    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):
    def _deco(func):
        def _deco():
            print ("before %s called [%s]" % (func.__name__,cls))
            cls.acquire()
            try:
                func()
            finally:
                cls.release()
        return _deco
    return _deco

@deco(Locker)  
def myfunc():
    print ("myfunc called!")

myfunc()
#b=deco(Locker)(myfunc)   --->相当于@deco(Locker)
#b()                      --->函数对象调用

装饰器学习九步法—第九步

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

代码示例:

#encoding:utf-8

“模块mylocker中的代码块”
class MyLocker(object):

    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):
    def _deco(func):
        def _deco(*args,**kw):
            print ("before %s called." % func.__name__)
            cls.acquire()
            try:
                return func(*args,**kw)
            finally:
                cls.unlock()            
        return _deco
    return _deco


#模块zhigang中的代码块
from mylocker import *

class Example(object):

    @lockhelper(MyLocker)
    def myfunc(self):
        print ("myfunc() called.")

    @lockhelper(MyLocker)     # --》 lockhelper(MyLocker)(_deco)
    @lockhelper(LockErex)     # --》 lockhelper(LockErex)(myfunc2) --》返回_deco函数对象 _deco 即myfunc2
    def myfunc2(self,a,b):
        print ("myfunc2() called.")
        return a+b

if __name__=="__main__":
    ex=Example()
    #ex.myfunc()
    #print ("*"*20)
    print (ex.myfunc2(1,2))
    #执行过程myfunc2(1,2)=lockhelper(MyLocker)(lockhelper(LockErex)(myfunc(1,2)))

内置装饰器

Python中内置的装饰器有三个:

staticmethod:定义实例方法为静态方法

classmethod:定义实例方法为类方法

property:对类属性的操作

猜你喜欢

转载自blog.csdn.net/weixin_37579123/article/details/85268440