python 装饰器

生效原理

1、@ 装饰器语法
装饰器实际是一个函数,或实现了‘call()’函数,可以像函数一样使用"()"直接调用的类。
装饰器语法的含义:以被装饰的函数为参数,调用装饰器函数。代码解释如下:

def a_new_decorator(a_func):
	print 'excute in a_new_decorator'
	return 'str_return_in_a_new_decorator'
	
@a_new_decorator
def a_function_need_decoration():
	print 'in a_function_need_decoration'
## @a_new_decorator 声明后,会执行 a_function_need_decoration = a_new_decorator(a_function_need_decoration), 
## 本质上是以被装饰函数名作为变量,重新赋值为装饰器函数的返回值

print 'a_function_need_decoration == %s' % a_function_need_decoration

输出:
excute in a_new_decorator
a_function_need_decoration == str_return_in_a_new_decorator

上述第一行输出是装饰器函数中 print 语句打印,@a_new_decorator声明时,装饰器函数就会被调用。第二行证明函数名作为变量被重新赋值为装饰器函数的返回值。本例中,装饰器函数返回了一个字符串,因此a_function_need_decoration变为一个字符串变量,变量值是‘str_return_in_a_new_decorator’。

2、用装饰器包装函数
装饰器一般用来“包裹”被装饰函数,示例如下。可以看到调用 a_function_requiring_decoration 函数时,实际调用的是装饰器返回函数wrapTheFunctn,a_function_requiring_decoration的调用语句被“包裹”在wrapTheFunctn 函数中。这样可以在不改动a_function_requiring_decoration代码情况下,为其增加新的功能(即在执行被装饰函数前后,执行一些其他的代码)。

def a_new_decorator(a_func):
    def wrapTheFunction():
        print("I am doing some boring work before executing a_func()")
        a_func()
        print("I am doing some boring work after executing a_func()") 
    return wrapTheFunction
    
@a_new_decorator
def a_function_requiring_decoration():
    """Hey you! Decorate me!"""
    print("I am the function which needs some decoration to "
          "remove my foul smell")
 
a_function_requiring_decoration()
#outputs: I am doing some boring work before executing a_func()
#         I am the function which needs some decoration to remove my foul smell
#         I am doing some boring work after executing a_func()
 
#the @a_new_decorator is just a short way of saying:
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)

如果我们运行如下代码会存在一个问题:

print(a_function_requiring_decoration.__name__)
# Output: wrapTheFunction

这并不是我们想要的!Ouput输出应该是"a_function_requiring_decoration"。这里的函数被warpTheFunction替代了。它重写了我们函数的名字和注释文档(docstring)。幸运的是Python提供给我们一个简单的函数来解决这个问题,那就是functools.wraps。我们修改上一个例子来使用functools.wraps:

from functools import wraps
 
def a_new_decorator(a_func):
    @wraps(a_func)
    def wrapTheFunction():
        print("I am doing some boring work before executing a_func()")
        a_func()
        print("I am doing some boring work after executing a_func()")
    return wrapTheFunction
 
@a_new_decorator
def a_function_requiring_decoration():
    """Hey yo! Decorate me!"""
    print("I am the function which needs some decoration to "
          "remove my foul smell")
 
print(a_function_requiring_decoration.__name__)
# Output: a_function_requiring_decoration

3、带参数的装饰器
示例:@test_outest_func(‘test para’) ,实际上不是装饰器带参数,这里有两个运算符,一个是函数调用运算符(),另一个是@。"()“优先级高于”@",因此先执行函数调用 test_outest_func(‘test para’),test_outest_func(‘test para’)的返回值是一个装饰器函数。

from functools import wraps

def test_outest_func(str):
    def a_new_decorator(a_func):
        @wraps(a_func)
        def wrapTheFunction():
            print("I am doing some boring work before executing a_func()")
            a_func()
            print("I am doing some boring work after executing a_func()")
        return wrapTheFunction
    return a_new_decorator

@test_outest_func('test para') 
def a_function_requiring_decoration():
    """Hey you! Decorate me!"""
    print("I am the function which needs some decoration to "
          "remove my foul smell")

应用场景

装饰器有很多应用场景,可以让代码管理更简单。部分场景举例如下。
1、授权
执行函数 ‘f’ 之前,先检查是否有权限

from functools import wraps
 
def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            authenticate()
        return f(*args, **kwargs)
    return decorated

2、日志

from functools import wraps
 
def logit(func):
    @wraps(func)
    def with_logging(*args, **kwargs):
        print(func.__name__ + " was called")
        return func(*args, **kwargs)
    return with_logging
 
@logit
def addition_func(x):
   """Do some math."""
   return x + x

result = addition_func(4)
# Output: addition_func was called

装饰器类

实现"call"函数, “call” 即装饰器函数。这里为什么不用先实例化logit类,还有待研究。

from functools import wraps
 
class logit(object):
    def __init__(self, logfile='out.log'):
        self.logfile = logfile
 
    def __call__(self, func): # 实现 __call__ 函数
        @wraps(func)
        def wrapped_function(*args, **kwargs):
            log_string = func.__name__ + " was called"
            print(log_string)
            # 打开logfile并写入
            with open(self.logfile, 'a') as opened_file:
                # 现在将日志打到指定的文件
                opened_file.write(log_string + '\n')
            # 现在,发送一个通知
            self.notify()
            return func(*args, **kwargs)
        return wrapped_function
 
    def notify(self):
        # logit只打日志,不做别的
        pass

@logit()
def myfunc1():
    pass

类的装饰器

类的装饰器,和函数的装饰器语义一致。下面代码中,@six.add_metaclass(Meta)语义是 MyClass = six.add_metaclass(Meta)(MyClass),即先调用函数six.add_metaclass(Meta),再six.add_metaclass(Meta)(MyClass)。

import six
@six.add_metaclass(Meta)
class MyClass(object):
    pass

参考:https://www.runoob.com/w3cnote/python-func-decorators.html

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值