python的装饰器总结

丶灬走出姿态 提交于 2020-01-13 06:34:36

前面碰到了装饰器的一些内容,这里总结一下。

要想对python更深入理解一些,装饰器是必须要掌握的内容。

闭包

必须说一下闭包这个概念,python的装饰器是python的闭包实现。

说一个通俗的理解,闭包就是能够读取其他函数的内部变量的函数,闭包是函数内部和外部链接的一个桥梁(这句话是百度百科摘过来的,我觉得不错)。我们也都知道python的的命名空间LEGB:查找顺序

L:local, 局部变量,函数结束,L也就没了

E:encolosing,这就是闭包的函数域

G:global,全局的变量

B:build in的内嵌的,比如系统关键字,type,int之类的

global num1
num1 = 1 # 全局
def test():
    num1 = 2 # 局部
    print num1
    num2 = 3 # enclosing
    num3 = 4 # local
    def func():
        print num2
    return func


fun = test()
fun()
print num1
print int # build in

装饰器

装饰器对函数或类进行“装饰”包裹,然后给对应的函数一些附加的功能,可以极大增加复用。

比如我们说一个add的函数,如果我们要在add中增加log,我们可以这么实现

def add(x, y):
    print "add operation"
    return x + y

这种方式太麻烦,如果很多函数都要加log,那就要增加很多很多,不利于维护。

或者我们可以这样

def logger(func):
    print "logger"
    return func

print logger(add)(1, 2)

但是这样似乎还是欠缺点,每次都要把func传入函数内,这个似乎更像是包裹函数了。

接下来我们尝试用装饰器,装饰器其实就是一个闭包函数,其实就是一个函数

def log(func):
    def wrapper(*args,**kwargs):
        print "logggggggggg"
        return func(*args,**kwargs)
    return wrapper

@log
def hello():
    print "keke"
hello()

这里可能会说,我希望log是可以传参的,装饰器也是可以解决这个问题的

def logger(info):
    def log(func):
        def wrapper(*args,**kwargs):
            print info
            return func(*args, **kwargs)
        return wrapper
    return log

@logger(info = "这是什么")
def hello():
    print "hello"
hello()

如果你在对这个研究深入一点的话,你会发现有点问题,那就是装饰器其实返回的是另外一个函数,这个会将原先函数的元数据信息给冲刷掉。

比如:

def log(func):
    def wrapper(*args,**kwargs):
        print func.__name__
        return func(*args,**kwargs)
    return wrapper

@log
def hello():
    print "hello"
hello()
tmp = log(hello)
print tmp.__name__

这两个是不一样的,我们可以用functools的wraps来再装饰一次,把func的元信息保存。

from functools import wraps
def log(func):
    @wraps(func)
    def wrapper(*args,**kwargs):
        print func.__name__
        return func(*args,**kwargs)
    return wrapper

@log
def hello():
    print "hello"
hello()
tmp = log(hello)
print tmp.__name__

除了上述这些之外,还有类装饰器,

类装饰器的好处,我也大概复制下其他人的说法(灵活度大、高内聚、封装性等优点),其实说白了,就是累装饰器比函数灵活度更高,更好用。

类装饰器主要利用的是__call__这个内置函数,只要对象具有该内置函数,则可以执行。

 

class Wrapper(object):
    def __init__(self,func):
        self._func = func
    def __call__(self, *args, **kwargs):
        print "begin"
        ret = self._func(*args, **kwargs)
        print "end"
        return ret

@Wrapper
def test():
    return "wo shi test"

print test()

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!