怎么创建和使用Python装饰器
本文小编为大家详细介绍"怎么创建和使用Python装饰器",内容详细,步骤清晰,细节处理妥当,希望这篇"怎么创建和使用Python装饰器"文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。
何时在 Python 中使用装饰器
当您需要更改函数的行为而不修改函数本身时,您将使用装饰器。一些很好的例子是当您想要添加日志记录、测试性能、执行缓存、验证权限等时。
当您需要在多个函数上运行相同的代码时,您也可以使用装饰器。这可以避免您编写重复的代码。
以下是用于创建 Python 装饰器的构建块
为了更好地理解装饰器的工作原理,您应该先了解一些概念。
函数是一个对象。因此,可以将函数分配给变量。可以从该变量访问该函数。
def my_function(): print('I am a function.')# Assign the function to a variable without parenthesis. We don't want to execute the function.description = my_function
# Accessing the function from the variable I assigned it to.print(description())# Output'I am a function.'
2. 一个函数可以嵌套在另一个函数中。
def outer_function(): def inner_function(): print('I came from the inner function.') # Executing the inner function inside the outer function. inner_function()
outer_function()# OutputI came from the inner function.
请注意,inner_function在outer_function内部. 如果我尝试执行inner_function外部,outer_function我会收到 NameError 异常。
inner_function()Traceback (most recent call last): File "/tmp/my_script.py", line 9, ininner_function()NameError: name 'inner_function' is not defined
3. 由于一个函数可以嵌套在另一个函数中,所以它也可以被返回。
def outer_function(): '''Assign task to student''' task = 'Read Python book chapter 3.' def inner_function(): print(task) return inner_functionhomework = outer_function()
homework()# Output'Read Python book chapter 5.'
4. 一个函数可以作为参数传递给另一个函数。
def friendly_reminder(func): '''Reminder for husband''' func() print('Don\'t forget to bring your wallet!')def action(): print('I am going to the store buy you something nice.')
# Calling the friendly_reminder function with the action function used as an argument.friendly_reminder(action)# OutputI am going to the store buy you something nice.Don't forget to bring your wallet!
如何创建 Python 装饰器
为了在 Python 中创建装饰器函数,我创建了一个将函数作为参数的外部函数。还有一个内部函数环绕装饰函数。
以下是基本 Python 装饰器的语法:
def my_decorator_func(func): def wrapper_func(): # Do something before the function. func() # Do something after the function. return wrapper_func
要使用装饰器,您可以将其附加到一个函数,就像您在下面的代码中看到的那样。我们通过将装饰器的名称直接放在我们想要使用它的函数上方来使用装饰器。你用一个@符号作为装饰器函数的前缀。
@my_decorator_funcdef my_func(): pass
这是一个简单的例子。此装饰器记录执行函数的日期和时间:
from datetime import datetimedef log_datetime(func): '''Log the date and time of a function''' def wrapper(): print(f'Function: {func.__name__}\nRun on: {datetime.today().strftime("%Y-%m-%d %H:%M:%S")}') print(f'{"-"*30}') func() return wrapper@log_datetimedef daily_backup(): print('Daily backup job has finished.') daily_backup()# OutputDaily backup job has finished.Function: daily_backupRun on: 2021-06-06 06:54:14---------------------------
如何在 Python 中为装饰器添加参数
装饰器可以将参数传递给它们。要向装饰器添加参数,我将*args 和 **kwargs添加到内部函数。
*args采取的任何类型的参数,数据类型不受限制,比如10,True,或'Brandon'。
**kwargs采取任何类型的关键字参数,例如count=99, is_authenticated=True, 或name='Brandon'。
这是一个带参数的装饰器:
def my_decorator_func(func): def wrapper_func(*args, **kwargs): # Do something before the function. func(*args, **kwargs) # Do something after the function. return wrapper_func@my_decorator_funcdef my_func(my_arg): '''Example docstring for function''' pass
装饰者隐藏他们正在装饰的函数。如果我检查__name__or__doc__方法,我们会得到一个意想不到的结果。
print(my_func.__name__)print(my_func.__doc__)# Outputwrapper_funcNone
为了解决这个问题,我将使用functools. Functools 包装将使用装饰函数属性更新装饰器。
from functools import wrapsdef my_decorator_func(func): @wraps(func) def wrapper_func(*args, **kwargs): func(*args, **kwargs) return wrapper_func@my_decorator_funcdef my_func(my_args): '''Example docstring for function''' pass
现在我收到了我期待的输出。
print(my_func.__name__)print(my_func.__doc__)# Outputmy_funcExample docstring for function
运行中的 Python 装饰器示例
我创建了一个装饰器来测量函数的内存和速度。我们将使用装饰器通过四种方法测试性能列表生成:范围、列表理解、追加和连接。
from functools import wrapsimport tracemallocfrom time import perf_counter def measure_performance(func): '''Measure performance of a function''' @wraps(func) def wrapper(*args, **kwargs): tracemalloc.start() start_time = perf_counter() func(*args, **kwargs) current, peak = tracemalloc.get_traced_memory() finish_time = perf_counter() print(f'Function: {func.__name__}') print(f'Method: {func.__doc__}') print(f'Memory usage:\t\t {current / 10**6:.6f} MB \n' f'Peak memory usage:\t {peak / 10**6:.6f} MB ') print(f'Time elapsed is seconds: {finish_time - start_time:.6f}') print(f'{"-"*40}') tracemalloc.stop() return wrapper@measure_performancedef make_list1(): '''Range''' my_list = list(range(100000))@measure_performancedef make_list2(): '''List comprehension''' my_list = [l for l in range(100000)]@measure_performancedef make_list3(): '''Append''' my_list = [] for item in range(100000): my_list.append(item)@measure_performancedef make_list4(): '''Concatenation''' my_list = [] for item in range(100000): my_list = my_list + [item]print(make_list1())print(make_list2())print(make_list3())print(make_list4())# OutputFunction: make_list1Method: RangeMemory usage: 0.000072 MB Peak memory usage: 3.693040 MB Time elapsed is seconds: 0.049359----------------------------------------Function: make_list2Method: List comprehensionMemory usage: 0.000856 MB Peak memory usage: 3.618244 MB Time elapsed is seconds: 0.052338----------------------------------------Function: make_list3Method: AppendMemory usage: 0.000448 MB Peak memory usage: 3.617692 MB Time elapsed is seconds: 0.060719----------------------------------------Function: make_list4Method: ConcatenationMemory usage: 0.000440 MB Peak memory usage: 4.393292 MB Time elapsed is seconds: 61.649138----------------------------------------
您也可以将装饰器与类一起使用。让我们看看如何在 Python 类中使用装饰器。
在这个例子中,注意没有@涉及任何字符。使用该__call__方法,在创建类的实例时执行装饰器。
此类跟踪查询 API 的函数已运行的次数。一旦达到限制,装饰器就会停止执行该函数。
import requestsclass LimitQuery: def __init__(self, func): self.func = func self.count = 0 def __call__(self, *args, **kwargs): self.limit = args[0] if self.count < self.limit: self.count += 1 return self.func(*args, **kwargs) else: print(f'No queries left. All {self.count} queries used.') return@LimitQuerydef get_coin_price(limit): '''View the Bitcoin Price Index (BPI)''' url = requests.get('https://api.coindesk.com/v1/bpi/currentprice.json') if url.status_code == 200: text = url.json() return f"${float(text['bpi']['USD']['rate_float']):.2f}"print(get_coin_price(5))print(get_coin_price(5))print(get_coin_price(5))print(get_coin_price(5))print(get_coin_price(5))print(get_coin_price(5))# Output$35968.25$35896.55$34368.14$35962.27$34058.26No queries left. All 5 queries used.
这个类将跟踪类的状态。
读到这里,这篇"怎么创建和使用Python装饰器"文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注行业资讯频道。