Python-装饰器详解

2023-10-26

装饰器

介绍

在Python中,装饰器是一种特殊的语法,用于修改或增强函数的功能。装饰器是Python的高级特性之一,它允许我们通过在不修改原函数代码的情况下,添加额外的功能或行为。

装饰器是一个函数,它接受一个函数作为参数,并返回一个新的函数。装饰器函数通常使用@符号放在要修饰的函数定义之前

python中的装饰器(decorator)一般采用语法糖的形式,是一种语法格式。比如:@classmethod,@staticmethod,@property,@wraps(),等都是python中的装饰器。

#装饰器: 是一种程序设计模式,主要用于给函数或者类添加一些额外的功能
#   又不希望通过继承或者修改源代码的方式去实现,那就使用装饰器

# 装饰器:不改变函数或类或者源代码的基础上,添加额外功能。
# 装饰器的本质就是闭包,它需要把一个callable对象(能够打括号调用的对象)作为参数转递进来。

使用

闭包

闭包:需要满足三个条件

  • 有内外函数
  • 外函数要返回内函数,而不是返回函数的调用结果
  • 内函数有引用外函数的变量

函数体内的局部变量,一般情况下,调用的时候生成,结束的使用释放
在闭包的条件下,局部变量不会随着调用的结束而释放

变量生命周期
局部变量 -- 函数的调用生成,函数调用完成释放
def func1():
    print("i am func1")


def outer():
    x = 30
    func1()
    print(f"x is {x}")

outer()
print(x)
def outer(x):
    a = 200
    def inner():
        print(x+a)
    return inner

d = outer(100)
#此时,d就是内函数,如果不调用d,就不会有输出
# d()
# 我们需要调用内函数才可以看到调用结果。

装饰器

看一段代码执行时间:

定义func1函数

def func1():
    time.sleep(1)
    print("i am func1")

在函数前后查看时间。

func1()

# 时间戳
start = time.time()
f = func1()
end = time.time()
print(f"执行函数花了{end-start}s")

使用装饰器查看时间

定义装饰器

def runtime(func):
    def inner(*args,**kwargs):          # *args, **kwargs  让装饰器更加通用。
        start = time.time()
        result = func(*args,**kwargs)
        end = time.time()
        print(f"函数执行花了{end-start}s")
        print(f"执行了{func.__name__}函数")
        return result                   # inner 函数返回原函数的返回值。
    return inner

定义函数

@runtime
def func2(a,b):
    time.sleep(2)
    print("i am func2")
    return a+b

func2(1,2)

注意:

  • 装饰器只能装饰函数或者类
  • 被装饰过的函数,不是原函数了,是装饰器返回的内函数
  • 添加的功能放在装饰器的内函数里面。

练习:

添加额外功能
统计运行时间
权限控制
日志记录

执行了什么函数  -- 写入日志,记录INFO 等级 ,写到文件和屏幕
计时功能装饰器
import functools
from logset import logger

def log(func):
    def inner_log(*args, **kwargs):
        logger.info(f"开始执行{func.__name__}函数")
        result = func(*args, **kwargs)
        logger.info(f"{func.__name__}函数,执行结束!")
        return result
    return inner_log

def runtime(func):
    @functools.wraps(func)
    def inner(*args,**kwargs):
        start = time.time()
        result = func(*args,**kwargs)
        end = time.time()
        print(f"函数执行花了{end-start}s")
        return result

    return inner

@log                # test_func1 = log ( runtime( test_func1() ) )
@runtime
def test_func1():
    time.sleep(1)
    print("this is func1")


test_func1()

装饰器带参数

自身不转入参数的装饰器,使用两层函数定义
自身转入参数的装饰器,使用三层函数定义

import time

user = {"root":"123456","admin":"admin123"}

def deco(username,passwd):
    def runtime(func):
        def inner(*args,**kwargs):
            if username in user and user[username] == passwd:
                if username == "root":
                    start = time.time()
                    result = func(*args,**kwargs)
                    end = time.time()
                    print(f"{func.__name__}执行花了{end-start}s")
                    return result
                else:
                    print("用户名密码不正确")
            else:
                print(f"用户:{username}没有权限")
        return inner
    return runtime

@deco(username="r",passwd="123456")
def add(a,b):
    time.sleep(1)
    return a+b

add(1,2)

类实现装饰器

import time

class A():
    def __init__(self,func):
        self.func = func

    def __call__(self, *args, **kwargs):
        start = time.time()
        result = self.func()
        end = time.time()
        print(f"{self.func.__name__}函数执行花了{end - start}s")
        return  result


@A              #   func1 = A(func1)   这是实例化
def func1():
    time.sleep(1)
    print("i am func1")


func1()

带参数的装饰器,用类实现

user = {"root":"123456","admin":"admin123"}
class A:
    def __init__(self,username,passwd):
        self.username = username
        self.passwd = passwd

    def __call__(self, func):
        def inner(*args, **kwargs):
            if self.username in user and user[self.username] == self.passwd:
                if self.username == "root":
                    start = time.time()
                    result = func(*args, **kwargs)
                    end = time.time()
                    print(f"{func.__name__}执行花了{end - start}s")
                    return result
                else:
                    print("用户名密码不正确")
            else:
                print(f"用户:{self.username}没有权限")
        return inner





@A(username = "root",passwd="123456")       #   a = A(username = "root"),func1 = a(func1)   这是实例化
def func1():
    time.sleep(1)
    print("i am func1")

func1()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python-装饰器详解 的相关文章

  • Python - 套接字错误,地址正在使用

    我目前正在尝试在 Xubuntu 12 10 x64 上设置 SiriServer 这不是重点 当我运行服务器时 python 返回错误 socket error Errno 98 Address already in use 默认情况下
  • 如何使用 Python 的 __import__ 函数执行相当于“从模块导入 *”的操作?

    给定一个带有模块名称的字符串 如何导入模块中的所有内容 就好像您调用了 from module import 即给定字符串 S module 如何获得与以下内容等效的内容 import S fromlist 这似乎没有按预期执行 因为它没有
  • 基于 Pandas 中的管道分隔列创建多个新列

    我有一个 pandas 数据框 其中有一个管道分隔的列 其中包含任意数量的元素 称为 零件 这些管道串中的元素数量从 0 到超过 10 个不等 所有管道串中包含的唯一元素的数量并不比行数小很多 这使得我无法在创建新列 对于每一行 我想创建一
  • 通过getattr动态获取dict元素?

    我想动态查询我想要检索的类中的哪些对象 getattr似乎是我想要的 并且它对于类中的顶级对象表现良好 但是 我还想指定子元素 class MyObj object def init self self d a 1 b 2 self c 3
  • TypeError:PyQt4.QtCore.QVariantAnimation 表示 C++ 抽象类,无法实例化

    我有这个 PyQt5 片段 我正在尝试将其转换为 PyQt4 PyQt5 版本运行得很好 但是当我尝试转换为 PyQt4 时 出现此错误 我删除了QtWidgets但我仍然收到此错误 我也尝试过实例化self animation QtCor
  • 使用 numba 计算向量和矩阵中的行之间的余弦相似度

    找到了这个gist https gist github com FedericoV 0e7d6d8c8794a99a7a42使用 numba 快速计算余弦相似度 import numba numba jit target cpu nopyt
  • 如何将 pymongo.cursor.Cursor 转换为字典?

    我正在使用 pymongo 查询一个区域内的所有项目 实际上是查询地图上一个区域内的所有场馆 我用了db command SON 在搜索球形区域之前 它可以返回一本字典 字典中有一个名为results其中包含场馆 现在我需要在一个正方形区域
  • 计算5个城市之间的地理距离以及每个城市所有可能的组合

    所以我有一个 csv 文件 其中包含 3 列 城市 纬度 经度 我已经使用此代码从这个 csv 文件在 python 中创建了一个数据框 data pd read csv lat long csv nrows 10 Lat data lat
  • Python 3 urllib 与请求性能

    我正在使用 python 3 5 并且正在检查 urllib 模块与 requests 模块的性能 我用 python 编写了两个客户端 第一个使用 urllib 模块 第二个使用 request 模块 它们都生成二进制数据 我将其发送到基
  • Python 中的类位于不同的文件中吗?

    与 Java 或 php 非常相似 我习惯将类与文件分开 Python 中也是同样的情况吗 另外 我应该如何命名该文件 像classname py一样小写还是像ClassName py一样 如果我想从此类创建一个对象 我是否需要做一些特殊的
  • Spark MLLib 存在问题,导致概率和预测对于所有内容都相同

    我正在学习如何将机器学习与 Spark MLLib 结合使用 目的是对推文进行情感分析 我从这里得到了一个情感分析数据集 http thinknook com wp content uploads 2012 09 Sentiment Ana
  • 向类添加属性的更 Pythonic 方式?

    我正在使用来自两个不同网页的数据集 但对于同一个人 数据集是合法信息 一些数据在第一页上可用 因此我使用正确的信息初始化被告对象 并将我当前没有数据的属性设置为null 这是班级 class Defendant object holds d
  • Python elasticsearch DSL 聚合/每个文档嵌套值的度量

    我试图找到 2 级嵌套中的最小值 每个文档单独的最小值 到目前为止 我能够进行聚合 计算搜索结果中所有嵌套值的最小值 但无需按文档进行分隔 我的示例架构 class MyExample DocType myexample id Intege
  • python中根据变量类型处理数据子集

    我将以下数据存储在 csv df sample csv 中 我将列名放在名为 cols list 的列表中 df 数据 样本 df data sample pd DataFrame new video BASE SHIVER PREFER
  • 当按下 flutter 中编写的按钮时,有没有办法运行 python 脚本?

    本质上 我想做的是 按下我在 Flutter 中编程的按钮 当按下该按钮时 Python 脚本应该开始在我的 Android 设备上运行 我想在 python 中使用 youtube dl 用于下载 Youtube 视频 库 但我想知道是否
  • Linux 中如何确定哪个进程正在使用某个端口

    我目前正在其默认端口上运行 RethinkDB 因为如果我将浏览器指向localhost 8080我看到 RethinkDB Web 界面 我想关闭 RethinkDB 并使用以下命令在另一个端口上重新打开它 port offset争论 然
  • 在 python matplotlib 中格式化损坏的 y 轴

    我正在 matplotlib 中处理一个 相当复杂的 条形图 它包含来自多个源的摘要数据 每个源都沿 x 轴标记 y 轴上有一系列结果 许多结果都是异常值 我尝试使用断开的 y 轴来显示这些结果 而不会使用以下组合来扭曲整个图表这个方法 h
  • Python:计算非整数的阶乘

    我想知道是否有一种快速的 Pythonic 的方法来计算非整数的阶乘 例如 3 4 当然 内置的factorial 函数在Math模块可用 但它仅适用于积分 我不关心这里的负数 你想用math gamma x http docs pytho
  • 如何将目录导入为 python 模块

    如果有目录 home project aaa 我知道它是一个Python包 那么 我如何通过知道它的路径来导入这个模块 这意味着 我希望代码能够正常工作 aaa load module home project aaa 我知道的唯一方法是
  • 用 Ruby 或 Python 解析 SVG 的库 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 SVG 是一个庞大的标准 它基于 XML 我过去曾将 SVG 解析为 XML 然而 有些事情很难 例如

随机推荐

  • 善于使用二阶思维

    事情往往不是你想象的那样 有时候 看似解决了问题 却在不经意间 引发了更严重的后果 帮助我们思考 决策 解决问题的最有效方法是 运用二阶思维 什么是二阶思维 一阶思维是单纯而肤浅的 几乎人人都能做到 二阶思维则是深邃 复杂而迂回的 能做到的
  • 异步调用,async await基本示例及项目中运用

    示例 async function asyncCall let a await interfaceFn console log 这里是同步 function interfaceFn return new Promise resolve re
  • Jackson中的自定义反序列化器和验证

    tl dr 将输入验证添加到Jackson中的自定义json解串器很重要 在RHQ中 我们在几个地方使用了Json解析 直接在as7 Wildfly插件中 或者通过RESTEasy 2 3 5间接在REST api中使用 已经很繁重了 现在
  • 构建高性能应用:Java与MongoDB的完美融合

    AI绘画关于SD MJ GPT SDXL百科全书 面试题分享点我直达 2023Python面试题 2023最新面试合集链接 2023大厂面试题PDF 面试题PDF版本 java python面试题 项目实战 AI文本 OCR识别最佳实践 A
  • windows 资源管理器已停止工作的解决办法

    问题现象描述 电脑开机输入密码后 加载很久 才跳转至解锁后的界面 但解锁后的界面不显示桌面 任务管理器提示 资源管理器已停止工作 尝试联机解决方案或者关闭程序都不奏效 一些快捷键比如win r win e都不起作用 但能ctr alt de
  • vue中 Error in mounted hook: "TypeError: __WEBPACK_IMPORTED_MODULE_0__assets_swiper_js__.default is n...

    个人小站点 https sundjly github io 在vue的项目中出现了以下错误 Error in mounted hook TypeError WEBPACK IMPORTED MODULE 0 assets swiper js
  • matplotlib可视化之饼图plt.pie()与plt.legend()中bbox_to_anchor参数的理解

    函数功能 表示离散变量各占比情况 调用方法 plt pie x explode None labels None colors None autopct None pctdistance 0 6 shadow False labeldist
  • matlab 小球随机分布,matlab空间内生成随机球体,并不重叠

    根据comsol上的奶酪模型 即在三维空间内生成小孔模型 想进一步控制生成的小孔互不重叠 但是运行不出来 大神们能帮我看看错误吗 代码是循环体部分的 奶酪中的小孔初始化参数 number of hols 80 初始化并定义奶酪内的小孔总数
  • matlab读取txt文档三行数据库,matlab将数据读取和写入txt文档

    matlab中打开文件 fid fopen 文件名 打开方式 说明 fid用于存储文件句柄值 若是fid gt 0 这说明文件打开乐成 另外 在这些字符串后添加一个 t 如 rt 或 wt 则将该文件以文本方式打开 若是添加的是 b 则以二
  • adb复制root到手机,怎样通过adb命令来root手机

    实战 Androidadb常用命令详解 ADB 全称Android Debug Bridge 是一个功能非常强大的工具 它位于Android SDK安装目录的platform tools 子目录下 ADB工具即可完成模拟器文件与电脑文件的相
  • win10 服务主机:DCOM服务器进程启动器 进程导致电脑卡死解决思路

    新买的笔记本 联想拯救者Y7000 系统 win10专业版 已经禁用了网上可搜的服务 没有win10开始菜单的磁条 原因 总是在开机一段时间后系统卡死 只能强制关机才可以 查找 后来开着任务管理器 放着看到底什么原因造成的 发现 服务主机
  • Ubuntu 16.04 上 CUDA_10.0及cuDNN的安装

    GPU Geforce GTX1060 驱动版本 418 56 最开始打算装CUDA 10 1 nvidia与cuda需相匹配 但是在运行cuda run后出现的用户许可证信息有问题 如图 但是CUDA 10 1与驱动版本是相匹配的 也没有
  • 排序算法总结(长期更新)

    1 最基础的排序算法 1 冒泡排序 思想 每次使用交换的方式将剩余元素中较大的元素放到一端 直到剩余元素为0的时候排序结束 include
  • PCL读取显示点云的两种方式

    读取点云的两种方式 PCL提供了两种pcd点云读写方式 其中PCD Point Cloud Date 点云数据 对应的文件格式为 pcd 是 PCL官方指定格式 具有 ASCII 和 Binary 两种数据存储类型 其中 ASCII 格式的
  • snipaste便捷截图小工具

    Snipaste是一个简单但强大的截图工具 也可以让你将截图贴回到屏幕上 下载并打开Snipaste 按下F1来开始截图 再按F3 截图就在桌面置顶显示了 还可以将剪贴板里的文字或者颜色信息转化为图片窗口 并且将它们进行缩放 旋转 翻转 设
  • 原码 反码 补码 移码

    原码 反码 补码都是有符号定点数的表示方法 一个有符号定点数的最高位为符号位 0是正 1是负 反码 原码 除符号位外 每位取反 补码 反码 1 反码 补码 1 移码 补码符号位取反 原码就是这个数本身的二进制形式 正数的反码和补码都是和原码
  • cmake错误:“未定义的引用”,“未声明的引用”

    描述 在编译代码的时候 经常会出现 未声明的引用 和 未定义的引用 之类的错误 原因 这种情况一般在编译的过程是不会出现问题 在链接的过程会出现这些问题 未声明的引用一般是头文件引入错误 或者找不到头文件 未定义的引用应该是找不到函数的实现
  • omv5-gitlab/gitlab-ce deploy

    omv5 gitlab gitlab ce yml example version 3 6 services web image gitlab gitlab ce latest restart always environment GITL
  • AWS架构图更新2019 - 最强大的AWS架构设计工具

    需要设计您的Amazon Web Services AWS 架构 今天我想介绍一下如何使用Visual Paradigm的云架构设计软件绘制AWS架构图快速而有趣 他们提供世界上最简单 最强大的AWS架构设计工具 全套AWS符号 创建专业的
  • Python-装饰器详解

    装饰器 介绍 在Python中 装饰器是一种特殊的语法 用于修改或增强函数的功能 装饰器是Python的高级特性之一 它允许我们通过在不修改原函数代码的情况下 添加额外的功能或行为 装饰器是一个函数 它接受一个函数作为参数 并返回一个新的函