Python 指南码农的世界

说一说那些我也不太懂的 Python 装饰器

2017-09-05  本文已影响68人  谢烟客

什么是装饰器?

简单点解释:装饰器就是一个可调用对象,其参数是被其装饰的可调用对象

是不是感觉有点绕?稍微具体一点解释:

因为函数在 Python 中是一等公民,所以一个函数可以接收另一个函数作为参数并返回一个新的函数,这样的一个函数就被称之为装饰器(这里先不讨论装饰类的情况)。

举个栗子:

#! /usr/bin/env python
# -*- coding: utf-8 -*-

# 定义一个装饰器
def add_prefix(func):
    def inner_func(args):
        return '/home/xieyanke/' + args
    return inner_func

@add_prefix
def test(path):
    return path

if __name__ == '__main__':
    print(test('factory'))    # 输出结果为:/home/xieyanke/factory

装饰器何时执行?

装饰器在 Python 模块导入时便执行了,所以装饰器在所有被装饰函数之前执行,也优先于被导入模块内所有可执行对象执行。

示例:my_decorator.py

#! /usr/bin/env python
# -*- coding: utf-8 -*-

def dec(func):
    print('my_decorator running...')
    return func

示例:main.py

#! /usr/bin/env python
# -*- coding: utf-8 -*-
from my_decorator import dec

@dec
def main1():
    print('func: main1 running')

def main2():
    print('func: main2 running')

if __name__ == '__main__':
    main2()
    main1()

# 执行结果:
# my_decorator running...
# func: main2 running
# func: main1 running

多个装饰器的执行顺序是什么?

假如一个函数被多个装饰器装饰,那么这些装饰器的执行顺序为自底向上执行

示例:main.py

#! /usr/bin/env python
# -*- coding: utf-8 -*-

def dec1(func):
    print("dec1 running...")
    return func

def dec2(func):
    print("dec2 running...")
    return func

@dec1
@dec2
def main():
    print('func: main running')

if __name__ == '__main__':
    main()

## 执行结果:
# dec2 running...
# dec1 running...
# func: main running
# 从结果可以看出多个装饰器的执行顺序为自底向上执行

装饰器如何接收参数?

如果我们使用一些其他框架例如:Flask ,经常发现框架中的装饰器是可以接收参数的。我们如何自定义一个可以接收普通参数的装饰器呢?

答案是:还真不能定义一个可以接收普通参数的装饰器。那么别人的框架是怎么实现的呢?其实这里面涉及到了闭包与自由变量的语法糖(关于闭包与自由变量后期会单独写一篇详细介绍,这里先带过了),那么要实现一个看着像可以接收普通参数的装饰器,需要先定义一个函数接收普通参数,然后返回这个函数内部实现的装饰器,这样就实现了一个看似可以接收普通参数的装饰器。

示例:main.py

#! /usr/bin/env python
# -*- coding: utf-8 -*-
def dec1(arg):
    def dec(func):
        print("dec1 receive args: " + arg)
        return func
    return dec

@dec1('arg_demo')
def main1():
    print('func: main1 running')

if __name__ == '__main__':
    main1()

最后说一说为什么要使用装饰器?

  1. 想用装饰器的内容替换被装饰函数的内容
  2. 想用装饰器的内容改进被装饰函数的内容
  3. 想把被装饰函数注册到某处
  4. 想在被装饰函数的执行前后做一些操作

qq群.jpg
上一篇 下一篇

猜你喜欢

热点阅读