python装饰器

2023-05-16

装饰器

一、概念

1. 装饰器(Decoration):
	    - 装饰器是一种设计模式,经常用来实现"面向切面的编程"(AOP: 实现在不修改源代码的情况下,给程序动态添加功能的一种技术)
	    
2. 装饰器的作用:
	    - 装饰器允许向一个现有的对象(函数)添加新的功能,同时又不改变其结构
	    - 可以抽离出大量的函数中的和业务无关的功能 

3. 应用场景:
		- 插入日志、性能测试、事务处理、缓存、中间件、权限控制等

举个栗子:现在需要计算某个函数的执行时间

import time


def fun1():
    start = time.time()
    s = 0
    for i in range(1, 100001):
        s += i
    print(f'和为:{s}')
    t = time.time() - start
    print(f'函数的执行时间为:{t:.10f}')


fun1()


def fun2():
    start = time.time()
    s = 1
    for i in range(1, 100001):
        s *= i
    print(f'乘积为:{s}')
    t = time.time() - start
    print(f'函数的执行时间为:{t:.10f}')


fun2()

如果要把计算时间的代码抽离出来,此时就可以使用装饰器来实现

import time
def get_time(func):
	def wrapper():
        start = time.time()
	    func()
        t = time.time() - start
        print(f'函数的执行时间为:{t}')
     return wrapper
    
@get_time    
def fun2():
    s = 1
    for i in range(1, 100001):
        s *= i
    print(f'乘积为:{s}')

fun2()  

二、装饰器详解

1、装饰器
装饰器:
1. 关键字:@,在被修饰的函数的前一行加入
2. 本质:装饰器的本质就是一个函数
3. 原理:在调用被装饰的函数时,被装饰的函数体的代码并不会被直接执行。而是在调用被装饰的函数时,将该函数传递给装饰器
2、装饰器的基本形式

并不是真正的装饰器(有问题)

# 装饰器函数必须要有一个参数,来接收被装饰的函数(名)
def my_decoration(func):
    #print('这里写要装饰的东西,要给被装饰的函数添加的功能')
    print('*'*10,'我是华丽丽的分隔线','*'*10)
    return func


@my_decoration
def f():
    print('这是一个函数')


# 这里调用被装饰的函数时,实际上先调用了装饰器,将函数本身
# 传递给装饰器函数,然后执行装饰器函数内部的代码
f()


@my_decoration
def f2():
    print('这是另一个函数')

f2() 
3、装饰器-内嵌函数

并不是真正的装饰器

def my_decoration(func):
    def wrapper():             # 这里和上述的基本形式本质上是一样
        print('这是要装饰的内容')
    wrapper()
    return func


@my_decoration
def f2():
    print('这是另一个函数')

f2() 
4、装饰器-闭包函数
def my_decoration(func):
    def wrapper():
        print('\n'+'*'*10,'start','*'*10)
        func() # 这是调用被装饰的函数
        print('*'*11,'end','*'*11,'\n')
    return wrapper


@my_decoration
def f():
    print('这是另一个函数')


f()
5、装饰器闭包原理剖析
# 闭包:内函数引用了外函数的局部变量,并且外函数返回了内函数对象本身
def outer(x):
    def inner():
        return x
    return inner

ot = outer('哈哈哈')
print(ot())
# 在上述的代码中,给外函数传递的是一个字符串类型的参数,其实也可给外函数传递一个函数对象
def outer(x):
    def inner():
        x()     # 这里实际是调用了f1()函数
    return inner


def f1():
    print('这是f1函数')


ot = outer(f1)
ot()
# @语法糖
def outer(func):
    def inner():
        print(1111111111)
        func()     # 这里实际是调用了f1()函数
        print(22222222)
    return inner


# def f1():
#     print('这是f1函数')
# ot = outer(f1)   # 1. 这是闭包的调用语法
# ot()

@outer          # 2. 这是Python的装饰器的语法糖
def f2():
    print('这是f2函数')

f2()

三、带参数的装饰器

之前实现的装饰器,给被装饰的函数添加的都是相同的功能,如果希望这个装饰对不同的函数作出不同的响应,此时就需要给装饰器传参数,在装饰器的内部根据参数的不同,作出不同的操作
def my_decoration(a):
    def wrapper(func):
        def inner():
            if a < 10:
                print(1111)
            else:
                print(2222)
            func()
        return inner
    return wrapper


@my_decoration(a=5)
def f1():
    print('这是第一个函数')


f1()

@my_decoration(a=20)
def f2():
    print('这是第二个函数')


f2()

四、类装饰器

装饰器不一定只能用函数来实现,也可以使用类来装饰,用法与函数装饰器区别不大,实质上是调用了类方法中__call__魔法方法
class logging:
    def __init__(self, func):
        print('__init__',func)
        self.__func = func

    def __call__(self):
        print(1111111)
        return self.__func()


@logging
def hello():
    print('hello 你好呀')


hello() # 调用了类装饰器中魔法方法 __call__  敲敲就会了

五、内置装饰器

Python语言本身也有一些装饰器,比如@property

class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    
gou = Person('二狗',18)
gou.age = 20  # 1. 属性暴露  2. 可以外界随意更改

修改:

class Person:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    def set_age(self, age):
        if isinstance(age, int):
            if 0 < age < 100:
                self.__age = age
            else:
                raise ValueError('年龄超出范围')
        else:
            raise TypeError('年龄类型错误')


    def get_age(self):
        return self.__age


gou = Person('二狗', 18)
gou.set_age('abc')      # TypeError: 年龄类型错误
print(gou.get_age())

再次修改:

class Person:
    同上....
    age = property(fget=get_age, fset=set_age)


gou = Person('二狗', 18)
gou.age = 200  # ValueError: 年龄超出范围
print(gou.age)
@property
# 使类中的方法可以像属性一样调用
class Person:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self,a):
        self.__age = a


gou = Person('二狗', 18)
gou.age = 20    # 调用 setter
print(gou.age)  # 调用 property

@staticmethod

将类中的方法设置为静态方法,它不需要创建实例对象,就可以使用类名来调用

class Person:
    x = 100
    xxxxxx...... 其它代码自己补
    
    @staticmethod
    def f():
        print(Person.x)   # 有一个方法不需要去访问实例属性
        print('静态方法')


Person.f() # 可以直接用类名调用

p = Person('Tom',18)
p.f()   # 也可以用对象调用
@classmethod
class Person:
    xxxxxxxxxxxxx..............
    @staticmethod
    def f():
        print(Person.x)
        print('静态方法')

    @classmethod
    def n(cls):  # 不用写类名 这里的cls就是类名
        print(cls,type(cls))
        print(isinstance(cls,Person))
        print(cls.x)

Person.n()

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

python装饰器 的相关文章

  • 仅将 pandas df 的前 N ​​行写入 csv

    如何仅将前 N 行或从 P 到 Q 行从 pandas 数据帧写入 csv 而不首先对 df 进行子集化 由于内存问题 我无法对要导出的数据进行子集化 我正在考虑一个逐行写入 csv 的函数 谢谢 Use head https pandas
  • 迭代字典按排序顺序返回键

    我有一个关于 python 如何处理字典中的数据的问题 假设我有一个简单的字典 其中一个数字作为键 一个数字作为值 如下所示 a 5 3 20 1 1 1 5 2 100 3 11 6 14 1 15 2 16 4 17 2 25 1 19
  • 如何旋转 xticklabel 以使每个 xticklabel 之间的间距相等? [复制]

    这个问题在这里已经有答案了 如何在 matplotlib 中旋转 xticklabel 以使每个 xticklabel 之间的间距相等 例如使用以下代码 import matplotlib pyplot as plt import nump
  • TensorFlow:在训练时更改变量

    如果我将输入管道从 feed dict 更改为 tf data dataset 如何在每次迭代后的训练期间更改网络内参数的值 澄清一下 旧代码看起来像这样 Define Training Step model is some class t
  • Python 非贪婪正则表达式

    我如何制作一个像这样的Python正则表达式 这样 给定 a b c d e 蟒蛇匹配 b 代替 b c d 我知道我可以使用 代替 但我正在寻找一种更通用的解决方案 使我的正则表达式更加干净 有没有办法告诉python 嘿 尽快匹配这个
  • Django模型更新或创建具有唯一约束的对象

    有一个模型 class Proxy models Model host models CharField max length 100 port models CharField max length 10 login models Cha
  • Django:使用条件 {% extends %} 使 {% block "div" %} 成为条件

    我想分享一个 AJAX 和常规 HTTP 调用之间的模板 唯一的区别是一个模板需要扩展 base html html 而另一个则不需要 我可以用 extends request is ajax yesno app base ajax htm
  • python中如何对多个条件进行排序?

    我有一个包含子列表的列表 如下所示 result helo 10 bye 50 yeah 5 candy 30 我想用三个条件来排序 首先 按子列表索引 2 中的最高整数 然后按子列表索引 1 中单词的长度 最后按子列表第 1 个索引中的字
  • Sympy:从表达式获取函数

    要从 sympy 表达式中获取所有变量 可以调用 free symbols在表达上 我想找回全部功能用在表达式中 例如 从y in from sympy import f Function f g Function g x Symbol x
  • Python XLWT:将列表写入单元格

    我正在尝试使用 Python XLWT 将列表写入单元格 这可能吗 我目前收到错误 Exception Unexpected data type
  • 在python中动态添加属性到__init__方法

    有什么方法可以定义一个函数 该函数可以在程序的稍后某个时刻向已经存在的属性添加新属性 init 方法 例如 下面我为家谱创建了一个类 每个实例都会创建一个根 class FamilyTree def init self rootObj se
  • 除非 POS 显式,否则 WordNetLemmatizer 不会返回正确的引理 - Python NLTK

    我正在对 Ted 数据集成绩单进行词形还原 我注意到一些奇怪的事情 并非所有单词都被词形还原 要说的是 selected gt select 哪个是对的 然而 involved gt involve and horsing gt horse
  • 如何处理 Django 中的错误

    我想让我的 django 应用程序尽可能对用户友好 并且我想处理适当的错误并让它推出类似于 javascript 中的警报的错误消息 我想在没有上传文件时执行此操作 因此 当按下上传按钮并且尚未上传任何内容时 将会发出一条警报消息 我的看法
  • 在 Python/Django 中将用户的 facebook/twitter 好友与网站用户进行比较

    我想知道是否有人可以帮助指导解决这个相当常见的问题的方法 我正在构建一个简单的网站 用户可以连接他们的 Twitter 帐户进行注册 我想创建一个界面 向他们显示哪些推特好友已经在使用该网站 因此 我可以获得用户的 Twitter 朋友列表
  • 错误:未找到线条魔术函数“%matplotlib”

    我刚刚按照 anaconda 的说明在 Mac MacOS 10 7 5 上安装了 IPythonhttp ipython org install html http ipython org install html 没有明显的错误 我现在
  • 中断 Select 以添加另一个要在 Python 中监视的套接字

    我正在 Windows XP 应用程序中使用 TCP 实现点对点 IPC 我正在使用select and socketPython 2 6 6 中的模块 我有三个 TCP 线程 一个读取线程通常会阻塞select 一个通常等待事件的写入线程
  • 为什么从 Pandas 1.0 中删除了日期时间?

    我在 pandas 中处理大量数据分析并每天使用 pandas datetime 最近我收到警告 FutureWarning pandas datetime 类已弃用 并将在未来版本中从 pandas 中删除 改为从 datetime 模块
  • 用枢轴点拟合曲线 Python

    我有下面的图 我想用 2 条线来拟合它 使用 python 我设法适应上半部分 def func x a b x np array x return a x b popt pcov curve fit func up x up y 我想用另
  • 需要在python中找到print或printf的源代码[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我正在做一些我不能完全谈论的事情 我
  • 将 python2.7 与 Emacs 24.3 和 python-mode.el 一起使用

    我是 Emacs 新手 我正在尝试设置我的 python 环境 到目前为止 我已经了解到在 python 缓冲区中使用 python mode el C c C c将当前缓冲区的内容加载到交互式 python shell 中 显然使用了什么

随机推荐

  • Oracle报错记录(持续更新)

    问题目录 问题1 xff1a ORA 01950问题2 xff1a ORA 12514问题3 xff1a ORA 28547 问题1 xff1a ORA 01950 问题描述 xff1a 对表空间无权限 解决 xff1a 以管理员身份运行c
  • Tengine-Lite在Nvidia AGX Xavier上的安装

    一 说明 由于工作需要 在Nvidia AGX Xavier上使用Tengine Lite引擎进行模型的推理使用 Tengine Lite是什么 Tengine 由 OPEN AI LAB 主导开发 xff0c 该项目实现了深度学习神经网络
  • 一份完整的软件测试报告

    基于软件发布测试编写一份完整的测试报告所包含的内容 xff1a 模板提取链接 xff1a https pan baidu com s 1l7opbNU7fwHXl9UacM4opQ 提取码 xff1a mgzo
  • 【STM32学习笔记】(10)——蜂鸣器实验详解

    蜂鸣器实验 蜂鸣器的简介 蜂鸣器是一种一体化结构的电子讯响器 xff0c 采用 直流电压供电 xff0c 广泛应用于计算机 打印机 复印机 报警器 电子玩具 汽车电子设备 电话机 定时器等电子产品中作发声器件 蜂鸣器主要分为 压电式蜂鸣器和
  • 计算机网络实验

    Ipconfig命令 1 实作一 Ipconfig命令通常被用户用来查看计算机中的ip地址 xff0c 子网掩码以及默认网关 与之类似的ipconfig all命令则是显示ipconfig中所有的详细信息 其中 xff0c ipconfig
  • 在linux系统下搭建鸿蒙bearPi的编译环境

    前言 xff1a 我是Linux使用的是Ubuntu18 04 进行环境配置的 xff0c 如果环境不同导致报错请自行网上搜索答案 1 首先先下载必要的插件 链接 xff1a https pan baidu com s 15E3SBXj g
  • keil玩儿51单片机时遇见的错误与警告

    一 错误1 错误展示 错误说明 xff1a 自己写的代码太大 xff0c 超过了keil5能够编辑的最大范围2048 xff1b 解决方法 xff1a 1 xff09 使用注册机 xff0c 破解keil5 xff1b 2 xff09 调整
  • Linux从入门到精通(Ubuntu 16.04)第一节实验

    第一节实验 命令操作 sudo su root 管理员身份 exit 退出管理员身份 xff0c 进入普通用户身份 shutdown 关机 reboot 重启 cd 进入根目录 cd 从当前目录后退一级 ls 查看当前目录文件及文件夹 cd
  • 计算机网络 第一节 基于 Windows 的 TCP/IP 实用程序:Ipconfig、Ping、Tracert、 Netstat、arp。

    了解基本的基于 Windows 的 TCP IP 实用程序 xff1a Ipconfig Ping Tracert Netstat arp 1 使用 ping 命令测试本地主机 TCP IP 的安装以及两台主机的连通情况 2 使用 ipco
  • IP地址,子网掩码,默认网关理解

    IP地址 xff0c 子网掩码 xff0c 默认网关 通俗来讲 xff1a IP 地址 xff0c 是标注一台电脑的身份 xff0c 如同每个人都有的身份证 xff1b 子网掩码表示所使用的网络属于哪种网络段 xff0c 两个IP地址同属于
  • Linux从入门到精通(Ubuntu 16.04)第二节实验

    1 重定向 cd home 在home文件夹 ls l gt test2 在home文件夹下新建了test2文件夹 xff0c 里面写入了home文件夹下的内容 2交换分区 注意 xff1a 要在cd root下进行 xff0c 当时在这里
  • Linux 从入门到精通(Ubuntu 16.04)第三节实验

    1 User 用户管理命令 xff08 1 xff09 adduser 添加用户 adduser a1 添加普通用户a1 adduser system home home a2 shell bin bash a2 添加系统用 xff0c 户
  • Labelme标签转COCO2017数据集格式

    以下代码是将Labelme标注软件标注的目标检测矩形框标签转换成COCO2017数据集格式进行训练 一 Labelme标注软件的安装 在Annaconda创建虚拟环境及安装Labelme conda create n labelme pyt
  • 深度剖析问题:Could not run ‘torchvision::nms‘ with arguments from the ‘CUDA‘ backend.

    问题 xff1a 使用YOLOv5进行测试的时候 xff0c 报错 xff1a Could not run 39 torchvision nms 39 with arguments from the 39 CUDA 39 backend x
  • 算法学习模板——素数问题、费马小定理、LCM/GCD和欧拉降幂

    万里之行 xff0c 始于足下 本博客总结近期学习到的部分数论模板 xff0c 以便于日后查询使用 作者水平有限 xff0c 难免存在疏漏不足 xff0c 恳请诸位看官斧正 倘若我的文章可以帮到你 xff0c 十分荣幸 当然 xff0c 以
  • NVIDIA显卡BUG解决 Unable to determine the device handle for GPU 0000:02:00.0: Unknown Error

    报错 实验室去年到今年断了几次电 xff0c 然后服务器上的2080Ti一直就感觉有点小毛病 属于是被折磨了几个月了 然后前两周断电后 xff0c 显卡就基本上完全用不了了 xff0c 经常服务器开机都会失败 并且就算服务器开机成功过后 x
  • 数据库E-R图基础概念

    E R图也称实体 联系图 Entity Relationship Diagram xff0c 提供了表示实体类型 属性和联系的方法 xff0c 用来描述现实世界的概念模型 ER模型的基本元素 实体 xff1a 用方框表示 xff0c 实体名
  • 51单片机蜂鸣器

    蜂鸣器分为两类 1 有源蜂鸣器 2 无源蜂鸣器 有源蜂鸣器比较简单 xff0c 只要有电流通过 xff0c 蜂鸣器就会发声 一般改变不了音调和音量 无源蜂鸣器要给一定频率的脉冲信号 xff0c 蜂鸣器才会发出声音 对于无源蜂鸣器只要改变频率
  • 数据分析----数据清洗

    文章目录 前言一 数据清洗是什么 xff1f 二 步骤1 选择列2 缺失值处理1 找到缺失值2 处理缺失值的方法 3 数据类型转化4 重复值处理 总结 前言 随着科技的不断发展 xff0c 数据在我们生活中越来越多 xff0c 面对繁杂的数
  • python装饰器

    装饰器 一 概念 1 装饰器 xff08 Decoration xff09 装饰器是一种设计模式 xff0c 经常用来实现 34 面向切面的编程 34 AOP 实现在不修改源代码的情况下 xff0c 给程序动态添加功能的一种技术 2 装饰器