前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >进阶的运维开发(一)- 装饰器

进阶的运维开发(一)- 装饰器

原创
作者头像
奔跑的骆驼
修改2019-12-11 18:31:26
3850
修改2019-12-11 18:31:26
举报
文章被收录于专栏:运维杂记运维杂记运维杂记

函数在python中作为一级对象,可以被当作参数传递,也可以作为函数返回,而装饰器就是利用这一特点,装饰器首先肯定是一个高阶函数,本质即是接受函数作为参数,返回一个函数。可以在函数执行的前后做一些操作,外层函数的作用域的变量(不包括全局变量)可以被内部函数应用,感觉又是一个闭包,但装饰器就是用一个函数装饰另一个函数,用来解决相同的一类问题。

理解装饰器

不带参数的装饰器

import time

def timeit(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        spend_time=time.time() - start_time
        return spend_time
    return inner

def sleep(x):
    time.sleep(x)

deco = timeit(sleep)
deco(3)
3.003096103668213

结合闭包的概念,将函数作为参数传递,将很容易理解上述过程,执行过程:timeit(sleep) -> inner(3),将sleep函数作为参数传入timeit,timeit返回inner函数,根据闭包(函数+应用环境),在外层函数的应用环境被引入inner内层函数,所以很顺利的sleep函数与inner函数就建立了连接,所以所装饰器也可以说是一个闭包。

试试语法糖:

import time

def timeit(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        spend_time=time.time() - start_time
        return spend_time
    return inner

@timeit
def sleep(x):
    time.sleep(x)

sleep(3)
3.0008034706115723

整个引用过程就更简单了,可以理解:sleep=timeit(sleep)

带参数的装饰器

import time

def timeit(offset=0):
    def outer(func):
        def inner(*args, **kwargs):
            start_time = time.time()
            func(*args, **kwargs)
            spend_time=time.time() - start_time + offset
            return spend_time
        return inner
    return outer

def sleep(x):
    time.sleep(x)

deco = timeit(1)
deco1 = deco(sleep)
deco1(3)
4.0014448165893555

根据不带参数的装饰器的理解,这个函数也是很好理解的。

试试语法糖:

import time

def timeit(offset=0):
    def outer(func):
        def inner(*args, **kwargs):
            start_time = time.time()
            func(*args, **kwargs)
            spend_time=time.time() - start_time + offset
            return spend_time
        return inner
    return outer

@timeit(1)
def sleep(x):
    time.sleep(x)

sleep(3)
4.0018510818481445

执行过程:timeit(1) -> outer(sleep) -> inner(3),其实说到这,装饰器就就是更多层的闭包。

多个装饰器叠加

首先我们要查看多个迭代器的的执行过程

def deco_1(func):
    print('enter deco_1')
    def inner1(*args, **kwargs):
        print('enter deco_1_inner')
        print(func.__name__)
        return func(*args, **kwargs)
    return inner1

def deco_2(func):
    print('enter deco_2')
    def inner2(*args, **kwargs):
        print('enter deco_2_inner')
        print(func.__name__)
        return func(*args, **kwargs)
    return inner2

@deco_1
@deco_2
def Print(*args, **kwargs):
    return args
enter deco_2
enter deco_1

Print(1, 2)
enter deco_1_inner
inner2
enter deco_2_inner
Print

(1, 2)

从这个例子中可以看出:Print(1, 2)=deco_1(deco_2(Print(1, 2)))

整个执行过程从下往上执行,注意看下输出的函数名的变化

不明白叠加装饰器的的使用场景,结合下面的使用场景看看:

import sys

def checkpass(func):
    def inner(*args, **kwargs):
        if pass_database.get(user, None) == password:
            func(*args, **kwargs)
        else:
            print('Password is not correct!')
            sys.exit(2)
    return inner

def checkuser(func):
    def inner(*args, **kwargs):
        if user in pass_database:
            func(*args, **kwargs)
        else:
            print('User is not presenet')
            sys.exit(3)
    return inner

@checkuser
@checkpass
def index(user, password):
    print("Hello {}!".format(user))

pass_database = {"dev": "1234567"}

user=input("请输入user:")
password=input("请输入pass:")
index(user, password)

类装饰器

使用类装饰器,是依靠类的魔术方法call实现,当使用@形式将装饰器附加到函数的时候就会调用此方法:

class deco:
    def __init__(self, func):
        self._func = func

    def __call__(self):
        print('enter')
        self._func()
        print('exit')

@deco
def Print():
    print(123)

保留原函数的信息

import time

def timeit(func):
	def inner(*args,**kwargs):
		start_time=time.time()
		func(*args,**kwargs)
		spend_time=time.time()-start_time
		return spend_time
	return inner

@timeit
def sleep(x):
	''' sleep '''
	time.sleep(x)

print(sleep.__name__,sleep.__doc__)

inner None

通过装饰器一装饰,原本sleep的函数信息就全部没了,成了一个新函数,而为了避免这种情况,functools中wraps可以将原本的函数属性全部更新到新函数中。

from functools import wraps
import time

def timeit(func):
	@wraps(func)
	def inner(*args,**kwargs):
		start_time=time.time()
		func(*args,**kwargs)
		spend_time=time.time()-start_time
		return spend_time
	return inner

@timeit
def sleep(x):
	''' sleep '''
	time.sleep(x)

print(sleep.__name__,sleep.__doc__)

sleep  sleep

以梦为马 不负韶华 归来仍是少年

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 理解装饰器
    • 不带参数的装饰器
      • 带参数的装饰器
      • 多个装饰器叠加
      • 类装饰器
      • 保留原函数的信息
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档