Decorators in Python

336 阅读1分钟

装饰器介绍

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。 它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。

制作一个装饰器

1.写一个hello world

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


def hello(func):
    def wrapper():
        print('Hello')
        func()

    return wrapper


def world():
    print('World')


helloWorld = hello(world)

if __name__ == '__main__':
    helloWorld()

输出

Hello
World

2.使用装饰器实现以上效果

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from functools import wraps


def hello(func):
    @wraps(func)  # 重写函数名字
    def wrapper():
        print('Hello')
        return func()

    return wrapper


@hello
def world():
    print('World')


if __name__ == '__main__':
    world()
    print(world.__name__)

输出

# without @wraps(func)
Hello
World
wrapper

# with @wraps(func)
Hello
World
world

细心的你已经察觉到两者代码的相似度如此之高,装饰器本质上是语法糖。

函数带参数的装饰器

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from functools import wraps


def hello(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print('Hello')
        return func(*args, **kwargs)

    return wrapper


@hello
def people(arg):
    print(arg)


@hello
def many_people(arg1, arg2):
    print(arg1)
    print(arg2)


if __name__ == '__main__':
    people('Jack')
    many_people('Tom', 'Mary')

输出

Hello
Jack
Hello
Tom
Mary

装饰器带参数

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from functools import wraps


def withArg(arg):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print(arg)
            return func(*args, **kwargs)

        return wrapper

    return decorator


@withArg('Hello')
def people(arg):
    print(arg)


if __name__ == '__main__':
    people('Jack')

输出

Hello
Jack

类装饰器

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


class ClassDecorator:
    def __init__(self, func):
        print('init')
        self.func = func

    def __call__(self, *args, **kwargs):
        self.func(self, *args, **kwargs)
        print('call')


class Decorators:
    name = ''

    def __init__(self, name):
        self.name = name
        print(self.name)

    @ClassDecorator
    def foo(self):
        print('foo')


if __name__ == '__main__':
    d = Decorators('isPlaying')
    d.foo()

输出

init
isPlaying
foo
call