python类装饰器和函数装饰器区别_python函数装饰器和类装饰器

函数装饰器

1、简单装饰器

def my_decorator(func):

def wrapper():

print('wrapper of decorator')

func()

return wrapper

def greet():

print('hello world')

greet = my_decorator(greet)

greet()

# 输出

# wrapper of decorator

# hello world

上述代码在 Python 中有更简单、更优雅的表示:

def my_decorator(func):

def wrapper():

print('wrapper of decorator')

func()

return wrapper

@my_decorator

def greet():

print('hello world')

greet()

# 输出

# wrapper of decorator

# hello world

2、带参数的装饰器

def my_decorator(func):

def wrapper(*args, **kwargs):

print('wrapper of decorator')

func(*args, **kwargs)

return wrapper

@my_decorator

def greet(message):

print(message)

greet('hello world')

# 输出

# wrapper of decorator

# hello world

3、自定义参数的装饰器

def repeat(num):

def my_decorator(func):

def wrapper(*args, **kwargs):

for i in range(num):

print('wrapper of decorator {}'.format(i))

func(*args, **kwargs)

return wrapper

return my_decorator

@repeat(4)

def greet(message):

print(message)

greet('hello world')

# 输出:

# wrapper of decorator 0

# hello world

# wrapper of decorator 1

# hello world

# wrapper of decorator 2

# hello world

# wrapper of decorator 3

# hello world

4、原函数还是原函数吗

试着打印出 greet() 函数的一些元信息:

greet.__name__

## 输出

'wrapper'

help(greet)

# 输出

Help on function wrapper in module __main__:

wrapper(*args, **kwargs)

greet() 函数被装饰以后,它的元信息变了。元信息告诉我们“它不再是以前的那个 greet() 函数,而是被 wrapper() 函数取代了”。

为了解决这个问题,通常使用内置的装饰器@functools.wrap,它会帮助保留原函数的元信息(也就是将原函数的元信息,拷贝到对应的装饰器函数里)。

import functools

def my_decorator(func):

@functools.wraps(func)

def wrapper(*args, **kwargs):

print('wrapper of decorator')

func(*args, **kwargs)

return wrapper

@my_decorator

def greet(message):

print(message)

greet.__name__

# 输出

'greet'

类装饰器

实际上,类也可以作为装饰器。类装饰器主要依赖于函数__call__(),每当你调用一个类的示例时,函数__call__()就会被执行一次。

class Count:

def __init__(self, func):

self.func = func

self.num_calls = 0

def __call__(self, *args, **kwargs):

self.num_calls += 1

print('num of calls is: {}'.format(self.num_calls))

return self.func(*args, **kwargs)

@Count

def example():

print("hello world")

example()

# 输出

num of calls is: 1

hello world

example()

# 输出

num of calls is: 2

hello world

我们定义了类 Count,初始化时传入原函数 func(),而__call__()函数表示让变量 num_calls 自增 1,然后打印,并且调用原函数。因此,在我们第一次调用函数 example()时,num_calls 的值是 1,而在第二次调用时,它的值变成了 2

装饰器的应用

身份认证 authenticate

日志记录

输入合理性检查 validation_check

缓存 lru_cache

通常使用缓存装饰器,来包裹这些检查函数,避免其被反复调用,进而提高程序运行效率,比如写成下面这样

你可能感兴趣的:(python类装饰器和函数装饰器区别_python函数装饰器和类装饰器)