1. 什么是装饰器
在 Python 中,装饰器(Decorator)是一种函数,它可以修改其他函数的功能。简单来说,装饰器就是对一个函数进行包装,以增强函数的功能,而不需要修改函数的本身。
装饰器在 Python 中应用非常广泛,一般用于:增加日志、性能分析、缓存、权限验证等方面。使用装饰器可以使代码简短、优雅、易读。
2. 装饰器的基本用法
本节将介绍装饰器的基本用法,以及如何使用装饰器进行函数增强。
2.1 基本语法
Python 中定义一个装饰器的方法如下:
def decorator_name(func):
def wrapper(*args, **kwargs):
# do something before the original function is called
result = func(*args, **kwargs)
# do something after the original function is called
return result
return wrapper
装饰器语法由 @ 符号和装饰器名称组成,放在函数定义的上方,如下所示:
@decorator_name
def func_name():
# do something
2.2 使用装饰器进行函数增强
通过装饰器可以对函数进行增强,如添加日志、性能分析等功能。下面是一个使用装饰器添加日志的例子:
import logging
def log_decorator(func):
def wrapper(*args, **kwargs):
logging.info('Calling function: {}()'.format(func.__name__))
result = func(*args, **kwargs)
logging.info('Function {}() returned: {}'.format(func.__name__, result))
return result
return wrapper
@log_decorator
def multiply(x, y):
return x * y
result = multiply(3, 4)
print(result)
上面的例子中,我们定义了一个名为 log_decorator 的装饰器,使用 logging 模块记录函数的调用和返回值。接着我们使用 @log_decorator 装饰 multiply() 函数,以增加函数的功能。最后我们调用 multiply() 函数,返回结果为 12。
3. 装饰器的实际应用
接下来我们将介绍装饰器的实际应用场景,并通过示例代码进行演示。
3.1 缓存函数结果
缓存函数结果可以避免在重复输入相同参数时反复调用函数进行计算。下面是一个缓存函数结果的装饰器:
def cache(func):
cached_results = {}
def wrapper(*args):
if args in cached_results:
return 'cached: ' + cached_results[args]
result = func(*args)
cached_results[args] = result
return result
return wrapper
@cache
def fibonacci(n):
if n == 0 or n == 1:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10))
print(fibonacci(10))
上面的例子中,我们定义了一个名为 cache 的装饰器,在缓存函数结果的基础上,使用 @cache 装饰 fibonacci() 函数以增加函数功能。我们调用 fibonacci(10) 两次,第一次直接计算,第二次从缓存中返回结果。
3.2 对函数进行重试
在网络请求等场景下,出现错误是常有的事。下面是一个对函数进行重试的装饰器:
import time
def retry(func):
def wrapper(*args, **kwargs):
attempts = 0
while True:
try:
result = func(*args, **kwargs)
return result
except Exception as e:
attempts += 1
if attempts == 3:
return 'Failed after 3 attempts'
print('Error occurred:', e)
time.sleep(1)
return wrapper
@retry
def fetch_url(url):
import requests
r = requests.get(url)
r.raise_for_status()
return r.text
print(fetch_url('http://example.com'))
上面的例子中,我们定义了一个名为 retry 的装饰器,在函数出现错误时进行重试。使用 @retry 装饰 fetch_url() 函数以增加函数功能。我们调用 fetch_url() 函数时,如果出现错误会进行自动重试,最多重试 3 次。
3.3 计算函数执行时间
计算函数运行时间是一个常见的需求,下面是一个计算函数执行时间的装饰器:
import time
def calculate_time(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
duration = end - start
print('Function {}() duration: {} seconds'.format(func.__name__, duration))
return result
return wrapper
@calculate_time
def count_to_n(n):
return sum(range(1, n+1))
print(count_to_n(10**6))
上面的例子中,我们定义了一个名为 calculate_time 的装饰器,用于计算函数执行时间。使用 @calculate_time 装饰 count_to_n() 函数以增加函数功能。我们调用 count_to_n() 函数时,计算函数的执行时间,并输出结果。
4. 使用类作为装饰器
除了函数,我们还可以使用类作为装饰器。下面是一个使用类作为装饰器的例子:
class Calculator:
def __init__(self, func):
self.func = func
self.calls = 0
def __call__(self, *args, **kwargs):
self.calls += 1
result = self.func(*args, **kwargs)
print('{} called {} times'.format(self.func.__name__, self.calls))
return result
@Calculator
def square(x):
return x * x
print(square(3))
print(square(4))
print(square(5))
上面的例子中,我们定义了一个名为 Calculator 的类,并使用它作为装饰器,以增加 square() 函数的功能。我们调用 square() 函数时,记录函数的调用次数,并输出结果。
5. 总结
装饰器是 Python 中非常实用的特性,可以用于增强函数的功能,使代码更加清晰和简洁。
装饰器是一种函数,可以修改其他函数的功能。
装饰器可以用来增加日志、性能分析等功能。
装饰器可以用来缓存函数结果、对函数进行重试、计算函数执行时间等。
除了函数,我们还可以使用类作为装饰器。