11、装饰器

简短的说:他们是修改其他函数的功能的函数。

一、一切皆对象

首先看一下python中的函数:

def hi(name=“hello”):
   return name + “world”

print(hi())
# output : ‘hello world’

# 我们可以将一个函数赋值给一个变量:
greet = hi
# 这里没有使用小括号,因为我们并不是在调用hi函数,而是将它放在greet里头。

print(greet())
# output : ‘hello world’

如果我们删掉旧的hi函数,看看会怎么样?

del hi
print(hi())
# output : NameError

print(greet())
# output : ‘hell world’
二、在函数中定义函数

python中可以在一个函数中定义另一个函数:

def hi(name=‘robot’):
   print(“now you are inside the hi() function”)

   def greet():
       return “now you are in the greet() function”

   def welcome():
       return “now you are in the welcome() function”

   print(greet())
   print(welcome())
   print(“now you are back in the hi() funciton”)

hi()

# output: now you are inside the hi() function
         now you are in the greet() function
         now you are in the welcome() function
         now you are back in the hi() funciton
  • 无论何时调用hi()函数,greet() welcome()函数将会被同时被调用。
  • 然后,greet()welcome()函数,在hi函数之外是不能访问的。
greet()
# output : NameError: name ‘greet’ is not defined.
三、从函数中返回函数

其实并不需要在一个函数中去执行另一个函数,我们也可以将其作为输出返回来:

def hi(name=“robot”):
   def greet():
       return “now you are in the greet() function”

   def welcome():
       return “now you are in the welcome() function”

   if name == “robot”:
       return greet
   else:
       return welcome

a = hi()
print(a)
# output : <function greet at ox89w8e8t7ew>

可以清晰的看到,a现在指向的是hi()函数中的greet()函数。

再次看看这个代码。在if/else语句中,我们返回greetwelcome,而不是greet()welcome()。因为当你把一对小括号放在后面,这个函数就会执行;然而如果你不放小括号在后面,那它可以被到处传递。并且可以赋值给别的变量而不去执行它。

四、将函数作为参数传递给另一个函数
def hi():
    return “hi robot”

def doSomethingBeforehi(func):
   print(“I am some boring work before executing hi())
   print(func())

doSomethingBeforehi(hi)

# output: I am some boring work before executing hi()
#         hi robot
五、第一个装饰器
def a_new_decorator(a_func):
   def wrapTheFunction():
       print(“I am some boring work before executing a_func())

       a_func()
       
       print(“I am some boring work before executing a_func())

   return wrapTheFunction

def a_function_requiring_decoration():
   print(“I am the function which needs some decoration to remove my foul smell”)

a_function_requiring_decoration()
# output: I am the function which needs some decoration to remove

a_function_requiring_decoration = a_new_decoration(a_function_requiring_decoration)

a_function_requiring_decoration()

# output:
# I am some boring work before executing a_func()
# I am the function which needs some decoration to remove
# I am some boring work before executing a_func()

上面的例程展示了装饰器在做的事情,它们封装了一个函数,并且用这样或那样的方式来修改它的行为。对于上面的例程,我们可以使用@来简化使用

def a_new_decorator(a_func):
   def wrapTheFunction():
       print(“I am some boring work before executing a_func())

       a_func()
       
       print(“I am some boring work before executing a_func())

   return wrapTheFunction

@a_new_decorator
def a_function_requiring_decoration():
   print(“I am the function which needs some decoration to remove my foul smell”)

a_function_requiring_decoration()

# output:
# I am some boring work before executing a_func()
# I am the function which needs some decoration to remove my foul smell
# I am some boring work before executing a_func()

这里的@a_newf_decorator 等价于:

a_function_requiring_decoration = a_new_decoration(a_function_requiring_decoration)

但是这样仍然会存在一个问题:

print(a_function_requiring_decoration.__name__)
# output : wrapTheFunction

这并不是我们想要的,我们希望output输出应该是:a_function_requiring_decoration

这里的函数被wrapTheFunction替代了。它重写了我们的函数名和注释文档(doctoring)。幸运的是python提供了一个简单的函数来解决这个问题,那就是functools.wraps。接下来看怎么使用:

from functools import wraps

def a_new_decorator(a_func):
   @wraps(a_func)
   def wrapTheFunction():
       print(“I am some boring work before executing a_func())

       a_func()
       
       print(“I am some boring work before executing a_func())

   return wrapTheFunction

@a_new_decorator
def a_function_requiring_decoration():
   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

规范示例:

from functools import wraps

def decorator_name(f):
   @wraps(f)
   def decorated(*args, **kwargs):
       if not can_run:
           return “Function will not run”
       return f(*args, **kwargs)
   return decorated

@decorator_name
def func():
   return(“Function is running”)

can_run = True
print(func())
# output: Function is running

can_run = False
print(func())
# output: Function will not run

注意:@wraps接受一个函数来进行修饰,并加入了复制函数名/注释文档/参数列表等功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。

六、装饰器的应用

1、日志是装饰器运用的一个亮点

from functools import wraps

# 定义一个装饰器
def logit(func):
   @wraps(func)
   def with_logging(*args, **kwargs):  # *args, **kwargs 是指 func 函数调用时传入的参数
       print(func.__name__. + “was called”)
       return func(*args, **kwargs)
@logit
def addition_func(x):
   return x + x

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

2、在函数中嵌入装饰器

回到日志的例子,并创建一个包裹函数,让我们指定一个用于输入的日志文件。

from functools import wraps

def logit(logfile=‘out.log’):
    def logging_decorator(func):
        @wraps(func)
        def wrapped_function(*args, **kwargs):
            log_string = func.__name__ + “ was called”
            print(log_string)
            # 打开logfile文件,并写入内容

            with open(logfile, ‘a’) as opened_file:
                #  现在将日志打到指定的logfile
                opened_file.write(log_string + ‘\n’)
            return func(*args, **kwargs)
        return wrapped_function
    return logging_decorator

@logit()
def myfunc1():
    pass

myfunc1()
# output: myfunc1 was called

3、装饰器类

python中类也可以用来构建装饰器。如下所示:

# coding=utf-8
from functools import wraps
import logging


class Log(object):
    def __init__(self):
        # 创建 logger
        self.logger = logging.getLogger('Logger')
        self.logger.setLevel(logging.INFO)

        # 写入日志
        fh = logging.FileHandler('./runtime.log')
        fh.setLevel(logging.INFO)

        # 输出到控制台
        ch = logging.StreamHandler()
        ch.setLevel(logging.INFO)

        # handler 输出格式
        formatter = logging.Formatter('[%(asctime)s][%(filename)s][%(levelname)s] ## %(message)s')
        fh.setFormatter(formatter)
        ch.setFormatter(formatter)

        # 绑定 handler
        self.logger.addHandler(fh)
        self.logger.addHandler(ch)

    def __call__(self, func):
        @wraps(func)
        def wrapped_function(*args, **kwargs):
            self.logger.info("%s is excuted!" % func.__name__)
            return func(*args, **kwargs)
        return wrapped_function

@Log()
def myfunc():
    print("hello log")


if __name__ == '__main__':
    myfunc()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值