IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> 一文带你精通Python装饰器 -> 正文阅读

[Python知识库]一文带你精通Python装饰器

1.引入

首先我们来用一个例子来引出什么是装饰器以及为什么要使用它.
下面是定义的一个Python function,仅仅是print一行字段

def f1():
    print("This is a function 1")

那么此时有了新的需求,需要在函数被调用执行时输出当时的时间,着很简单只需要调用一下其他类库就可以,代码如下

from datetime import datetime


def f1():
    print(datetime.now())
    print("This is a function 1")

ok, 此时需要确实是达到了,但是假如我们除了f1()还有f2()、f3()…等等方法都需要增加这个需求呢?难道需要给每个方法都去加上这一条输出时间语句?显然这种解决方案是不合适的. 并且它违背了对修改封闭,对扩展开放的原则

因此, 为了解决有多个函数都需要输出被调用时间的需求,并且满足开闭原则, 我们可以使用Python 函数式的特性 专门编写一个函数用来打印时间.

from datetime import datetime


def f1():
    print("This is a function 1")


def f2():
    print("This is a function 2")


def print_current_time(func):
    print(datetime.now)
    func
    

print_current_time(f1())
print_current_time(f2())

上面的代码可以更好实现我们的需求, 这样做逻辑上是没问题的,但是我们调用的时候不再是调用真正的业务逻辑 f1,f2 函数,而是换成了 print_current_time 函数,这就破坏了原有的代码结构, 现在我们不得不每次都要把原来的那个 f 函数作为参数传递给 print_current_time 函数,那么有没有更好的方式的呢?当然有,答案就是装饰器。

2.装饰器

1.简单装饰器

首先来看看什么是简单装饰器

import time


def decorator(func):
    def wrapper():
        print(time.time())
        func()

    return wrapper


def f():
    print("This is a function")
f = decorator(f)
f()

decorator 就是一个装饰器,它一个普通的函数,它把执行真正业务逻辑的函数 f 包裹在其中,看起来像 f 被 decorator 装饰了一样,decorator 返回的也是一个函数,这个函数的名字叫 wrapper。
这个例子乍一看跟上一步使用的print_current_time方法没有太大区别,甚至没有print_current_time方法简单明了,别急再往下看看@语法糖

2.@语法糖

@ 符号是装饰器的语法糖,它放在函数开始定义的地方,这样就可以省略最后一步再次赋值的操作。

上面的例子我们可以进行一些改变,如下

import time


def decorator(func):
    def wrapper():
        print(time.time())
        func()

    return wrapper

@decorator
def f():
    print("This is a function")
f()

如上所示,有了 @ ,我们就可以省去f = decorator(f)
这一句了,直接调用 f()即可得到想要的结果。你们看到了没有,f() 函数不需要做任何修改,只需在定义的地方加上装饰器,调用的时候还是和以前一样,如果我们有其他的类似函数,我们可以继续调用装饰器来修饰函数,而不用重复修改函数或者增加新的封装。这样,我们就提高了程序的可重复利用性,并增加了程序的可读性。

3.*args、**kwargs

可能有人问,如果我的函数 f 需要参数怎么办?很简单只需要同样的给装饰器中wrapper方法加上参数即可
比如:

import time


def decorator(func):
    def wrapper(func_name):
        print(time.time())
        func(func_name)

    return wrapper

@decorator
def f(func_name):
    print("This function name is" + func_name)


f('first')

同理,如果f方法接收的是多参数只需要将wrapper方法参数变为:*agrs即可

   def wrapper(*args):
       print(time.time())
       func(*args)

同样的,f方法如果还可以接收关键字参数,也只需将wrapper方法参数加上:**kw即可

    def wrapper(*args, **kw):
        print(time.time())
        func(*args, **kw)

4.@wraps

当我们使用了装饰器后,方法名会发现改变

@decorator
def f(func_name):
    print(f.__name__)

输出结果是:wrapper,说明此时f的方法名已经变成wrapper,如果想要让使用装饰器的方法名不改变,只需在wrapper方法上加上@wraps

from functools import wraps

def decorator(func):
    @wraps(func)
    def wrapper():
        func()

    return wrapper
@decorator
def f():
    print(f.__name__)

f()

其实仔细想想,为什么使用装饰器后方法名称会改变?
因为本来最后执行的方法就是wrapper,对比着简单装饰器,我们其实只是用@语法糖看起来是执行的f方法而已。

5.优化装饰器写法

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-07-13 17:25:22  更:2021-07-13 17:25:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/5 0:40:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码