一篇文章带你了解Python中的装饰器

作者:宇宙之一粟 时间:2022-11-23 14:00:14 

前言

本文将带你学习装饰器在 Python 中的工作原理,如果在函数和类中使用装饰器,如何利用装饰器避免代码重复(DRY 原则,Don’t Repeat Yourself )。

Python 中的装饰器是什么

装饰器在 Python中是一个非常强大和有用的工具,因为它允许程序员修改函数或类的行为。装饰器允许我们包装另一个函数,以扩展包装函数的行为,而无需修改基础函数定义。这也被称为元编程,因为程序本身在程序运行时会尝试修改自身的另一部分。

装饰器是语法糖: 在代码中利用更简洁流畅的语法实现更为复杂的功能。

我们知道,Python 一切皆对象。这意味着 Python 中的函数可以用作参数或作为参数传递。一等函数的属性:

  • 函数是 Object 类型的实例。

  • 可以将函数存储在变量中。

  • 可以将该函数作为参数传递给另一个函数。

  • 可以从函数中返回函数。

  • 可以将它们存储在数据结构中,例如哈希表,列表等。

让我们看一个这样的例子。

def hello():
   print('Welcome to Python Decorator!')
another_hello = hello()
another_hello
# Welcome to Python Decorator!

定义了一个 hello() 函数,然后将 hello 函数分配给 another_hello 变量,然后调用这个变量,得到的结果是 hello 函数被执行。

既然 Python 中的函数是对象,那么除了可以简单的调用之外,就可以把函数作为对象传递给另一个函数。

def print_welcome():
   print('Welcome to Python Decorator!')
def print_hello(func):
   def inner():
       print('Hello!')
       func()
   return inner
decorated = print_hello(print_welcome)
decorated()
# Hello!
# Welcome to Python Decorator!

语法糖

但是,上面的代码使用了内部函数我们可以通过简单地用装饰器函数 print_hello() 来装饰 print_welcome() 函数。

装饰器可以简化我们的操作。功能完全一样,但它的代码更简洁。即通过 @ 符号简化装饰器的使用,如下所示:

def print_hello(func):
   def inner():
       print('Hello!')
       func()
   return inner
@print_hello
def print_welcome():
   print('Welcome to Python Decorator!')
print_welcome()
# Hello!
# Welcome to Python Decorator!

通过这样做,我们能够消除将一个函数显式传递到另一个函数中的使用。Python 装饰器隐式处理这一点。

使用 Python 装饰器修改函数行为

使用 Python 装饰器对函数进行计时

为了演示它们的实用性,让我们构建一个函数,该函数采用另一个函数并对其执行进行计时。在这里,使用装饰器的好处是它允许我们遵循 DRY 编程原则。

装饰器可用于测量函数执行所需的时间。 如果你定义一个简单的睡眠函数,以计算该函数的运行时。

一篇文章带你了解Python中的装饰器

import time
def timeit(func):
   def timed():
       start = time.time()
       result = func()
       end = time.time()
       print(f'Program took {(end - start) * 1000}s to run')
       return result
   return timed
@timeit
def print_welcome():
   print('Welcome to Python Decorator!')
print_welcome()
# Welcome to Python Decorator!
# Program took 0.0s to run

分析一下上面的代码:

  • 定义了一个函数 timeit() 接受另一个函数

  • 该函数还有另一个内部函数 timed()

  • 函数跟踪开始时间,执行修饰函数,跟踪结束时间,计算差值并返回结果

  • 最后,外层函数返回内层函数

当我们将此装饰器函数应用于我们的函数 print_welcome() 时,首先会返回欢迎问候语,然后显示执行时间。

使用 Python 装饰器将有用信息记录到终端

与上面的例子类似,我们可以在程序运行时使用装饰器将有用的信息打印到终端。例如,我们可能想知道正在运行哪个函数以及当前时间。也可以使用装饰器传递到日志文件:

from datetime import datetime
def log_info(func):
   def inner():
       print(f'Starting run at {datetime.now()}')
       print(f'Running {func.__name__}')
       func()
   return inner
@log_info
def print_welcome():
   print('Welcome to Python Decorator!')
print_welcome()
# Starting run at 2022-03-27 23:26:38.473310
# Running print_welcome
# Welcome to Python Decorator!

在上面的示例中,在运行函数之前,我们的装饰器打印当前日期和时间以及将要运行的函数的名称。如果您正在运行较长的脚本,并且只是想知道程序的位置,这可能很有用。

Web app 中使用的装饰器

让我们以 Web 应用程序的用例为例。当您在 Flask 中构建 Web 应用程序时,您总是会编写 url 路由。 每条路线都是 Web 应用程序中的特定页面。 打开页面 /about 可能会调用 about_page() 方法。

一篇文章带你了解Python中的装饰器

@app.route("/about")
def about_page():
 return "Website about nachos"

将参数传递给 Python 装饰器

到目前为止,您已经学习了如何创建一些有用的 Python 装饰器。然而,这些装饰器都没有传入参数。在本节中,您将学习如何创建接受参数的 Python 装饰器。

为此,我们将允许在 Python 语法魔术解压缩。使用 func_name(*args,**kwargs),它将解压缩所有参数和所有关键字参数。通过在装饰器中使用它,可以确保装饰器将接受任意数量的参数或关键字参数。这使得它们在重复使用时更加实用。

def print_function_name(func):
   def inner(*args, **kwargs):
       print(f'Running {func.__name__}...')
       return func(*args, **kwargs)
   return inner
@print_function_name
def add_nums(a, b):
   print(a + b)
add_nums(1, 2)
# Running add_nums...
# 3

上述方法的美妙之处在于它同时接受位置和关键字参数。因此,即使我们以以下任何格式执行该函数,该函数也将运行:

  • add_nums(1024, 2020)

  • add_nums(1024, b = 2021)

  • add_nums(a = 1024, b = 2222)

使用多个 Python 装饰器

关于 Python 装饰器的一个有趣的方式是:可以同时使用多个装饰器。这意味着您可以将多个装饰器应用于单个函数。为了理解这一点,来看一个例子:

def one(func):
   def inner(*args, **kwargs):
       print('1')
       return func(*args, **kwargs)
   return inner
def two(func):
   def inner(*args, **kwargs):
       print('2')
       return func(*args, **kwargs)
   return inner
@one
@two
def speak(text):
   print(text)
speak('Hello')
# 1
# 2
# Hello

我们的装饰器函数所做的唯一事情就是打印出数字 1 和数字 2。通过将装饰器 @one 放在 @two 之前,您可以将 two()包装的函数包装为 one()。为了说明这一点,您可以切换顺序以查看如何修改行为:

# Changing decorator order
@two
@one
def speak(text):
   print(text)
speak('Hello')
# 2
# 1
# Hello

通过首先放置 @two 装饰器,该函数成为最外层的函数。

  • Primer on Python Decorators – Real Python

  • Python Decorators Introduction - Python Tutorial (pythonbasics.org)

来源:https://juejin.cn/post/7080549589589164045

标签:python,装饰器
0
投稿

猜你喜欢

  • python学生信息管理系统实现代码

    2021-07-01 03:41:18
  • Python pyinotify模块实现对文档的实时监控功能方法

    2023-04-15 08:13:52
  • Oracle数据库中表空间的基本管理操作小结

    2024-01-26 23:18:26
  • Python实现的数据结构与算法之基本搜索详解

    2021-07-25 03:47:44
  • Python如何处理异常报错方法(建议收藏!)

    2022-08-09 03:19:13
  • Pytorch实现LSTM和GRU示例

    2022-02-08 09:14:44
  • 二级域名的解析指向ASP源码

    2007-10-19 19:13:00
  • python的help函数如何使用

    2023-12-21 10:46:48
  • 使用python的pandas读取excel文件中的数据详情

    2023-06-18 11:26:11
  • tensorflow使用freeze_graph.py将ckpt转为pb文件的方法

    2023-01-31 15:31:05
  • Python序列化基础知识(json/pickle)

    2021-04-24 01:09:34
  • 用python将word文档合并实例代码

    2021-08-13 06:17:01
  • Python对象体系深入分析

    2022-10-25 11:29:33
  • python递归计算N!的方法

    2021-11-11 21:11:31
  • python使用turtle库绘制树

    2022-04-14 09:09:06
  • 前端优化,让你的网页显示的更快更流畅

    2009-06-08 13:09:00
  • 详细讲解删除SQL Server日志的具体方法

    2008-12-09 14:32:00
  • 压缩包密码破解示例分享(类似典破解)

    2022-10-17 17:03:37
  • 利用Go语言实现Raft日志同步

    2024-03-15 02:55:20
  • javascript实现九宫格相加数值相等

    2024-04-17 10:32:53
  • asp之家 网络编程 m.aspxhome.com