Python学习之装饰器

Python搭建聊天机器人 Python用AIML搭建聊天机器人AIML,全名为Artificial Intelligence Markup Language(人工智能标记语言),是一种创建自然语言软件代理的XML语言,是由Richard Wallace和世界各地的自由软件社区在1995年至2002年发明的。它的雏形是一个名为”A.L.I.C.E.” (“Artificial Linguistic Internet Compu 阅读详情

第一部分:装饰器定义

装饰器本身也是一个函数,装饰器是用来修饰函数的,可以简单的理解为装饰器是对一个函数稍加改造而实现某些特定的功能

第二部分:知识储备

函数即变量

首先看一下几个定义的简单函数及后续操作
重点看函数定义的位置有什么不同!
1.
代码

def Alice():
   print("this is Alice")

def Bob():
    print("this is bob")
    Alice()
Bob()

执行结果

this is bob
this is Alice

分析:Alice定义在Bob的上边,Bob在定义中引用了Alice,按解释器的解释规则来看,代码是自上而下一行一行执行的,这样的执行过程完全没有问题

代码

def Bob():
   print("this is bob")
   Alice()
def Alice():
   print("this is Alice")
Bob()

执行结果

this is bob
this is Alice

分析:这里我么将Alice定义在了Bob的下边,此时有些人会困惑了,程序是一行一行执行的,那么在执行到def Bob()这段语句中,里面调用的Alice是没有定义的,为什么没有报错呢?这就是我想让大家get到的一点!

经过以上两个例子,大家应该已经发现了这其中的一些问题,现在我们对上述出现的情况进行解释

(1)首先我们来分析一下函数的定义结构

def Alice():                   ###定义函数名
   print("this is Alice")      ###定义函数体

函数的整个定义结构,分为函数名和函数体
(2)打印下面的这两种情况

def Alice():
   print("this is Alice")
print(Alice)
print(Alice())

执行结果

<function Alice at 0x000001DA9D75E0D0>   ###是一个内存地址
this is Alice                            ###执行Alice()产生的输出
None                                     ###此处是Alice()这个函数的返回值,因为没有设置,所以默认是空

分析
第一个print输出的是一个内存地址,这个地址就是Alice()这个函数存放的地址,里面存放的就是函数定义中的函数体。
举一个简单的例子
我们定义一个x=10,x是一个变量名,10是一个数值,定义的过程就是,为x这个变量在内存中开辟一个空间,然后将10这个数值存入到里面
函数的定义也是类似的,def Alice()就是先在内存中申请一块空间(这块空间在我们看来可以叫做Alice),然后将函数体(实际执行的部分)放入到里面。当调用函数时,其实就是将函数中的函数体中的语句都执行一遍!

这样就解释了上边为什么第二种情况是可行的,因为函数的定义语句(def Alice())只是将函数体存在了指定的空间中,而并没有实际的去运行它。(可以通过设置断点的方法来一步一步的看程序的执行过程)。这样就简单的说明了什么是函数即变量了!

函数嵌套

函数嵌套的定义:在一个函数中再定义一个函数,再定义的这个函数只在父函数内有意义,即作用域是有限的,只在父函数内有效
下面看一个函数嵌套的简单例子

def Alice():
   print("this is Alice")
   def Truddy():
      print("this is Truddy")
   Truddy()

Alice()
this is Alice
this is Truddy

高阶函数

判断是否是高阶函数,有两个标准
1.如果传入函数A的参数是一个函数,那么函数A是高阶函数
2.如果函数A的返回值是一个函数,那么函数A是高阶函数
下面看两个例子
例子一,函数的参数是一个函数

def Bob():
   print("this is Bob")
def Alice(func):
   print("this is Alice")
   print("-------------")
   func()
Alice(Bob)   ###这里传入的是函数的内存空间,如果按这种写法Alice(Bob())会出现一些问题,有兴趣的可以自己试一下,这里就不再解释了

this is Alice
-------------
this is Bob

例子二,函数的返回值是一个函数

def Bob():
   print("this is Bob")
def Alice(func):
   print("this is Alice")
   print("-------------")
   return func
Truddy = Alice(Bob)       ##Alice(Bob)先执行,然后返回Alice的返回值,我们定义的返回值是传入的函数
print("*************")
Truddy()
this is Alice
-------------
*************
this is Bob

第三部分:装饰器

一.根据装饰器的功能对装饰器的一些要求
装饰器的功能就是在不改变原函数的源代码和调用方式的情况下,来实现对原函数的功能的增强
两点重要的要求:
(1)不改变原函数的代码
(2)不改变原函数的调用方式
为了满足这两个要求,我们就要用到前面我们所讲的函数嵌套和高阶函数了!
二.不改变原函数的代码的实现
假设我们为一个输出函数增添一个统计函数完成时间的功能,我们可以这么写

import time
def Bob():
   print("this is Bob")
def Alice(func):
   start_time=time.time()
   func()
   time.sleep(3)
   end_time = time.time()
   print("the cost of time is {}".format(end_time-start_time))
Alice(Bob)

执行结果如下

this is Bob
the cost of time is 3.0007195472717285

我们完成了Bob这个函数的输出功能,同时增添了统计时间的功能,也没有修改Bob函数的源代码,但是Bob函数的调用方式却改变了,原本只需要Bob()即可,但现在还要将Bob传入Alice(),写作Alice(Bob)。

接下来我们再看一下不改变函数调用方式的实现

三.不改变函数的调用方式的实现

import time
def Bob():
   print("this is Bob")
def Alice(func):
   start_time=time.time()
   return func
   time.sleep(3)
   end_time = time.time()
   print("the cost of time is {}".format(end_time-start_time))
Bob=Alice(Bob)
Bob()
this is Bob

我们通过函数返回的方式,满足了不改变函数的调用方式,但是问题是也没有给函数增加功能

其实我们离目标已经很接近了!让我们再加上函数嵌套看看效果会怎么样!

四.使用高阶函数和函数嵌套来实现装饰器

import time
def Bob():
   print("this is Bob")
def Alice(func):
   def wrapper():
    start_time=time.time()
    func()
    time.sleep(3)
    end_time = time.time()
    print("the cost of time is {}".format(end_time-start_time))
   return  wrapper
Bob=Alice(Bob)
Bob()
this is Bob
the cost of time is 3.000948190689087

上述例子中,我们使用高阶函数解决了不修改源代码的就增添功能这一问题,又使用函数嵌套解决了不改变函数的调用就可以实现的这一问题
所以可以认为装饰器的实现实际上就是高阶函数和嵌套函数组合成的一个起修饰作用的函数

但是,如上每次函数的执行都需要进行Bob=Alice(Bob) 的转换,有一定的繁琐,我们可以用以下的方式来实现简化

import time

def Alice(func):
   def wrapper():
    start_time=time.time()
    func()
    time.sleep(3)
    end_time = time.time()
    print("the cost of time is {}".format(end_time-start_time))
   return  wrapper

@Alice              ############添加的部分在这 本质是在使用Bob()之前先执行命令 Bob=Alice(Bob)
def Bob():
   print("this is Bob")
Bob()

我们可以在我们要被装饰的函数之上,写上@+装饰器名称
需要注意的是,@Alice实际上是执行了一次指令,这样就需要Bob的定义放在Alice的下面了,不然会有找不到Alice的报错

五.装饰器的进阶
以上我们举得例子中函数都是没有参数的,那么如果我们需要往函数中传参数的时候该怎么办呢
以下给出操作

第一代

import time

def Name_time(func):
   def wrapper():
    start_time=time.time()
    func()
    time.sleep(3)
    end_time = time.time()
    print("the cost of time is {}".format(end_time-start_time))
   return  wrapper

@Name_time
def Name(name):
   print("my name is {}".format(name))
Name("Bob")


执行结果

Traceback (most recent call last):
  File "C:/Users/fuxiangyu/PycharmProjects/fuxiangyu/基础实验/标准输出.py", line 15, in <module>
    Name("Bob")
TypeError: wrapper() takes 0 positional arguments but 1 was given

Process finished with exit code 1

执行之后,发现报错,原因是我们并没有定义往Name_time()中的wrapper()传参数,但是缺传入了一个参数(关于为什么时wrapper报错,是因为此时Name()是wrapper函数的返回,可以理解为现在的Name是指向wrapper()的内存空间的)

第二代

import time

def Name_time(func):
   def wrapper(name):
    start_time=time.time()
    func(name)
    time.sleep(3)
    end_time = time.time()
    print("the cost of time is {}".format(end_time-start_time))
   return  wrapper

@Name_time
def Name(name):
   print("my name is {}".format(name))
Name("Bob")

执行结果

my name is Bob
the cost of time is 3.000530242919922

我们在wrapper()函数的定义中加入了参数,使得函数可以正确的运行了,但是有个问题,就是如果我想拿这个装饰器也去修改别的函数,别的函数可能有参数,可能没有参数,可能有一个或者多个函数的情况下该怎么做呢?
接下来我们再来对其功能进行加强

第三代

import time

def timer(func):
   def wrapper(*arr,**kwargs):
    start_time=time.time()
    func(*arr,**kwargs)
    time.sleep(3)
    end_time = time.time()
    print("the cost of time is {}".format(end_time-start_time))
   return  wrapper

@timer
def Pure_out():
   print("Python is the best language")

@timer
def Name(name):
   print("my name is {}".format(name))

@timer
def Name_and_Age(name,age):
   print("my name is {} ,my age is {}".format(name,age))

Pure_out()
Name("boy")
Name_and_Age("Bob","21")

执行结果

Python is the best language
the cost of time is 3.000469446182251
my name is boy
the cost of time is 3.00105357170105
my name is Bob ,my age is 21
the cost of time is 3.0003440380096436

通过向wrapper函数传入(*arr和**kwargs)来实现,可以接收任何形式的输入

至此,装饰器的基本介绍到此为止!

AI人工智能-Python实现人机对话 【前言】   AI   在人工智能进展的如火如荼的今天,我们如果不尝试去接触新鲜事物,马上就要被世界淘汰啦~   本文拟使用Python开发语言实现类似于WIndows平台的“小娜”,或者是IOS下的“Siri”。最终达到人机对话的效果。 【实现功能】   这篇文章将要介绍的主要内容如下:   1、搭建人工智能--人机对话服务端平台   2、实现调用服务端平台进行人机对话交... 阅读详情

相关推荐

保姆级教程:在Ubuntu 22.04上从零安装SUMO并运行第一个交通仿真

本教程详细介绍了在Ubuntu 22.04系统上从零安装SUMO交通仿真软件并运行第一个仿真的完整流程。涵盖环境准备、PPA源安装、核心组件验证、首次仿真案例运行以及进阶配置技巧,特别针对netedit路网编辑器和地图格式转换等实用工具进行重点讲解,帮助用户快速掌握SUMO在交通仿真领域的应用。

weixin_30546189的博客 422

入门版

为了方便记录与管理,这篇是所有入门版的集合 第一篇:循环语句与If语句

Alice的python记录 418

CNN经典网络模型(二):AlexNet简介及代码实现(PyTorch超详细注释版)

CNN经典网络模型之一:AlexNet,本文包含其简介及代码,在PyTorch中实现,进行超详细注释,适合新生小白阅读学习~

qq_43307074的博客 2万+

python装饰器返回参数_Python装饰器

无返回值的装饰器:importtimedef timer(func): #无返回值装饰器def test_extra(*args, **kwargs): #传入参数长度可变(参数多少都可用)start_time = time.time() #装饰器添加功能:计时func(*args, **kwargs) ...

weixin_42128015的博客 615

sap销售发货的流程_SAP销售订单发货后如何实现发票的自动创建?

问SAP销售订单发货后如何实现发票的自动创建?答业务场景有些快消零售企业,SAP系统单据量大,单据金额少,一般在销售发货后即可确认收入。此时无需人工在系统内操作VF01或者VF04进行开票操作,可将该操作设置成后台作业进行自动批量开票,具体操作如下:1、定义任务:VF06输入完以上信息,点击保存进入以下界面:说明:当前日期的意思是“开票的日期”等于“系统电脑中的当前日期”当前日期+/-...

weixin_42358409的博客 3363

告别手动处理:用 Bruker NSMatlabUtilities 工具箱批量分析 AFM 力曲线数据的实战案例

本文介绍了如何使用 Bruker NSMatlabUtilities 工具箱实现 AFM 力曲线数据的批量分析,解决传统手动处理耗时且易出错的问题。通过实战案例展示工具箱的核心功能,包括数据读取、力曲线分析和可视化,帮助科研人员提升数据处理效率和准确性。

weixin_28362173的博客 213

python-03 基本语法

基本语法 1.Python中严格区分大小写 2.Python中一行就是一条语句,换行结束 3.Python中每一行语句不要过长(规范中建议每行不要超过80个字符) preference->setting里添加 "rulers":[80] 4.多行编写时以\结尾 5.Python是缩进严格的语言,在Python中不要随便写缩进 6.Python中使用#来表示注释 7.如果需要打印\,则需要在它前面加入反斜杠,即增加\\ 字符串 1.%s 在字符串中表示任意字符 %s是占位符,%后面是占位

Alice_HappyAlice的博客 352

寄存器与计数器设计(Verilog)

always @(posedge Reset or posedge Clock)//请在括号中补充敏感信号列表。always @(negedge Resetn , posedge Clock)//请在括号中补充敏感信号列表。always @(negedge Resetn,posedge Clock)//请在括号中补充敏感信号列表。//为了便于自动评测,请勿更改n的值。//为了便于自动评测,请勿更改n的值。//为了便于自动评测,请勿更改n的值。//为了便于自动评测,请勿更改n的值。

M_inherit的博客 362

python 装饰器学习与实践

从图中我们可以看到,第1 ,函数执行后,正常执行了装饰器的语句;假设一个场景,在对多个函数进行装饰的同时又希望加入额外的不同处理,比如对于上一小节的test1、test2、test3,假设他们都需要一个传入一个系数和一个名称才能进行后续计算。但我们程序已经写好,如果对每个函数内容都去做try-except处理无疑是很费时的,这里我们就可以用装饰器对函数进行包装。装饰器,对现有函数进行装饰,可以在函数执行前、后编写程序来增加功能,实际就是在函数外层嵌套一层函数。

qq_41437305的博客 931

撸毛笔记-朴朴超市 v1.01

朴朴超市 v1.01脚本地址:自动签到和组队赚朴分, 朴分可以抵扣50%的金额组队瓜分需要4人成团, 每个号每天只能开团和入队各一次每天跑一两次即可使用扫码或自己想办法捉refreshToken扫码获取token: (先微信进入朴朴超市小程序并登录注册过账号再扫码)把获取的refreshToken和备注(非必须)填到文件pupuCookie.txt里(第一次运行会自动创建), 多账号换行或&或@隔开。

xiaoshun007的专栏 1805

15、降维算法:原理、实现与应用

本文深入介绍了多种降维算法,包括线性方法如主成分分析(PCA)和线性判别分析(LDA),以及非线性方法如Sammon映射、t分布随机邻域嵌入(t-SNE)和自编码器。文章通过C++库Dlib和Shogun展示了这些算法的具体实现,并结合图像压缩和数据可视化等实际案例,分析了不同算法的适用场景。此外,还探讨了降维算法的选择策略、优化改进方法以及未来发展趋势,为读者提供了全面的技术理解和应用指导。

lemon的博客 115

Python中装饰器是什么?为什么要学习装饰器?

装饰器是什么?为什么要学习装饰器?装饰器用于拓展原来函数功能的一种函数,在不改变原函数名或类名的情况下给函数增加新的功能。给已有函数增加额外功能的函数,它本质上就是一个闭包函数,我们学习得主要目的是掌握装饰器的语法格式。

Python栈 521

推免保研夏令营/预推免面试记录—北航网安

链接:https://pan.baidu.com/s/1vkP3EzbVrCc8a7wgQuUZgQ?链接:https://pan.baidu.com/s/1n4EFS2c9WLAfQn91CP4j2g?链接:https://pan.baidu.com/s/1VVNNSfcNDWjXhVhH3MtNjA?上面五个比例基本为:1:5:2:1:1。面试时间:当天上午面试,但是没面完,下午吃了饭之后又继续面试。--来自百度网盘超级会员V5的分享。--来自百度网盘超级会员V5的分享。

admin的博客 3011

python学习——装饰器

个人学习记录 搬运自:b站up主正月点灯笼的视频 例程代码:判断质数 import time # 装饰器的格式 传入的函数func。 def wrapper(): 和return wrapper是固定格式 def display_time(func): def wrapper(*args): # 调用函数的参数在这里通过args被传入进来 t1 = time.time() result = func(*args) # 把函数的返回值先记录下来放到result中,否则没有返回值,同时传入的参数在这里

qq_38604310的博客 267

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Python装饰器入门_Python编程学习

Python允许你,作为程序员,使用函数完成一些很酷的事情。在Python编程学习中,函数是一等对象(first-class object),这就意味着你可以像使用字符串,整数,或者任何其他对象一样使用函数。 例如,你可以将函数赋值给变量: >>> def square(n): ... return n * n; >>> square(4) 16 >&g...

chen801090的博客 207

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Python学习-装饰器

_new__方法允许在类创建时拦截,并返回任意对象(包括闭包函数)。这种实现方式非常灵活。示例:函数装饰器的实现name }!") greet("Alice") # 输出: # Before the function call # Hello, Alice!name }!") greet("Alice") # 输出: # Before the function call # Hello, Alice!示例:类装饰器的实现# 定义一个动态生成的类,继承自原始类。

weixin_45550881的博客 972

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Python学习之——装饰器

Python学习之——装饰器

selfsongs 2万+

python装饰器教学_Python装饰器学习(九步入门)

这是在Python学习小组上介绍的内容,现学现卖、多练习是好的学习方式。第一步:最简单的函数,准备附加额外功能 # -*- coding:gbk -*-'''示例1: 最简单的函数,表示调用了两次'''def myfunc():print("myfunc() called.")myfunc()myfunc()第二步:使用装饰函数在函数执行前和执行后分别附加额外功能# -*- coding:gbk...

weixin_39765869的博客 64

Python学习难点之装饰器

知识补充 不定长参数 def test(*args, **kwargs): print(args) print(kwargs) test(3,'k',a=4,b='w') #(3, 'k') args是元组(未命名参数) #{'a': 4, 'b': 'w'} kwargs是字典(命名参数) 作用域 在python中,作用域分为两种:全局作用域和局部作用域。 全局作用域是定义在文件级别的变量...

南雁北归的博客 408

Python装饰器学习(九步入门)

Python装饰器学习(九步入门) Python装饰器学习(九步入门) 这是在Python学习小组上介绍的内容,现学现卖、多练习是好的学习方式。 第一步:最简单的函数,准备附加额外功能 1 2 3 4 5 ...

avtcpm1927的博客 84

Python装饰器学习

一、装饰器是什么 在代码运行期间不改变原函数定义的基础上,动态给该函数增加功能的方式,称之为装饰器。是一个很著名的设计模式 二、装饰器的使用范围 较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概况的讲,装饰器就是为已有的函数添加额外的功能。 三、装饰器和闭包 另外装饰器其实是个闭包,闭包就是:...

sunjinjuan的博客 314

【python学习】python的生成器和装饰器

https://github.com/JackKoLing/python_notes_with_ten_days 俗话说:“好记性不如烂笔头”,多写写多记记,总不会错。多一些不为什么的坚持,少一些功利主义的追求。对于环境的配置,可以参考以下两篇: win10版 @小保,公众号:CV之道 【深度学习环境配置】手把手实战配置深度学习环境(win10版) Linux版 @小保,公众号:CV之道 【深度学习环境配置】手把手实战配置深度学习环境(Ubuntu20.04版) 【声明】:学习笔记基于互联网上各种

learning CV 1247

python学习笔记------装饰器进阶

装饰器进阶 is_admin装饰器:判断传入的参数是否root; import functools import inspect # 利用inspect函数可以获取类中的docs,类名,类以及类的代码,是否存在的模块等等。 def is_admin(fun): # fun=add_student @functools.wraps(fun) def wrapper(*...

L--certain 316

Python 装饰器学习

Python装饰器学习(九步入门) 这是在Python学习小组上介绍的内容,现学现卖、多练习是好的学习方式。 第一步:最简单的函数,准备附加额外功能 1 2 3 4 5 6 7 8 # -*- coding:gbk -*- '''示例1: 最简单的函数,表示调用了两次''' defmyfunc(): ...

weixin_30471065的博客 83
上一篇: 浅谈存储之RAID的基本概念
下一篇: Python学习之生成器
flat0809
博客等级 码龄9年 45粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值