python中的装饰器

python语言中的装饰器应该算是这门语言中的一个难点了,作为一个初学者,好像也知道是怎么回事,可是否真正理解了,那还得存疑。最近偶然看到老男孩的Egon老师的视频,我才觉得真正明白装饰器是怎么一回事了。Egon老师那种抽丝剥茧式的讲解,真是让人耳目一新。虽然有些时候略显繁琐,但对于一个困难知识点来说,再没有这种方式更好的讲解了。接下来,我就着刚看过视频的热乎劲儿,把我对装饰器的理解记录下来,以防止哪一天忘记了。

  • 什么是装饰器
    - 装饰器一种特殊对象,可以给其它对象添加功能,而不改变所装饰对象的使用方式。比如说:如果一个函数被一个装饰器装饰,那么从用户的角度来看,应该感觉不到有任何变化,函数的调用方式,参数以及返回值都不发生任何变化。
    - 装饰器用到了一个Python中的一个重要概念:闭包。什么是闭包?条件有两个:一是一定要有一个内部函数。二是这个内部函数一定要访问包含这个内部函数的外层函数的变量。
    - 还利用了Python中的函数的特性:可以作为参数传递,也可以作为返回值被返回。
  • 如何来写一个装饰器(以函数装饰器为例)
    - 我们先来考虑,如何给一个函数增加功能,却不改变它的调用方式。
# sol3 - 1: 通过在内外层函数中使用两次(*args, **kwargs),可以把外层函数的参数原封不动地传递到内层。
# 从而就可以把内层函数的参数写活,但是变更了调用方式,要通过wrapper来调用index

def wrapper(*args, **kwargs):
    start = time.time()
    index(*args, **kwargs)
    stop = time.time()
    print(stop - start)


wrapper('xiaolee', 'zd')

# sol 3 -2: 要想不改变函数的调用方式,只能通过在wrapper函数外再包上一层函数。这个方案还不能接收内层函数的返回值。
def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        func(*args, **kwargs)
        stop = time.time()
        print(stop - start)
    return wrapper


index = timer(index)
index('ggg', 'dddd')


# sol3 - 3:通过res变量接收内层函数的返回值,并作为wrapper函数的返回值返回。
def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        stop = time.time()
        print(stop - start)
        return res
    return wrapper


index = timer(index)
print(index('zz', 'yy'))
# sol 4: 语法糖
def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        stop = time.time()
        print(stop - start)
        return res
    return wrapper

@timer
def index(x, y):
    time.sleep(1)
    print('heloo %s, your company %s' % (x, y))

index('xxxx', 'ccccc')     
  • 带参数的装饰器
# 带参装饰器:实际上,一层闭包就可以将一个参数向内传递一层。
# 以加简单的认证功能为例
def authentication():
    user = input('Please input your username: ').strip()
    password = input('Please input your password: ').strip()
    if user == 'zylee' and password == 'wlsoft':
        print('authentication successful!!!')
        return True
    else:
        print('authentication failed!!!')
        return False

def auth(db_style):
    def deco(func):
        def wrapper(*args, **kwargs):
            # auth code
            if db_style == 'mysql':
                if authentication():
                    res = func(*args, **kwargs)
                    return res
            elif db_style == 'file' and authentication():
                if authentication():
                    res = func(*args, **kwargs)
                    return res
            else:
                print("error!!!!")
        return wrapper
    return deco

# @auth('mysql')这一行的功能:先执行auth('mysql'),将deco作为返回值返回。实际上@作用在了deco上。
# @的作用有二:一是将所装饰的函数的地址作为参数传给deco。二是deco(index)的返回值赋给index。运行之后,相当于执行wrapper函数。
@auth('mysql')   
def index(x, y):
    print('hello, %s and %s' % (x, y))

index('a', 'b')
原文地址:https://www.cnblogs.com/xiaolee-tech/p/13474622.html