fpython-笔记(五)装饰器、匿名函数
一、装饰器
装饰器,这个器就是函数的意思,连起来,就是装饰函数,装饰器本身也是一个函数,它的作用是用来给其他函数添加新功能,比如说,我以前写了很多代码,系统已经上线了,但是性能比较不好,现在想把程序里面每个函数都加一个功能,用来统计每个函数的运行时间是多少,找出来运行比较慢的函数,来优化代码,或者一个功能在调用之前必须登陆,就需要添加一个新的功能,来统计程序的运行时间,那这样的话,就得修改每个函数了,需要改代码,但是代码特别多,改完了公司倒闭了,这时候装饰器就能排上用场了,它可以不改变原有的函数,原来的函数和原来一模一样,什么都不需要改变,只需要在函数外部加上调用哪个装饰器就可以了。so,装饰器的作用就是不改变原来函数的调用方式,不改变原来函数的代码,给它增加了一个新功能。但是不改变函数,给它增加新功能,那是不可能的,装饰器只不过是偷偷改变了原来的函数而已,而原来的函数不知不觉。
说白了就是函数嵌套+高阶函数
作用:就是在不改变原有函数的调用方式,入参的情况下给函数添加新功能
偷偷摸摸的给函数加上新功能,但是不改变原来的函数
使用装饰器需要了解的知识:
*1 函数即变量,意思是在python中函数可以当一个变量来用,函数名就是一个变量,这个变量存的实际上是这个函数的内存地址,在调用的时候从函数名里面这个内存地址找到这个函数。()代表调用函数,如果只打印函数名的话实际上就是打印了一下内存地址。
def test():
print('nihao')
print(test) # 打印函数的内存地址
test() # 调用函数`<function test at 0x0000000002383E18>
*2 高阶和嵌套函数
之前的章节提过,实际上装饰器就是高阶函数和嵌套函数的结合体
下面我们写一个简单的装饰器,用来计算函数的运行时间。
import time
def bar():
time.sleep(3)
print('测试执行时间')
def test_time(func)
start_time = time.time()
func()
stop_time = time.time
print('函数的运行时间是%s'%(stop_time - start_time))
test_time(bar)
运行结果:
测试执行时间
函数的运行时间是3.000171661376953
但是这样的话,我们每次要调用test_time(bar),而不是直接调用bar(),所以就改变了函数的调用方式。
这时我们就想到了装饰器。如果不修改调用代码,也就是意味着调用bar(),需要和test_time(bar)一样的
效果,如果test_time(bar)并咩有直接产生调用函数的效果,而是返回一个函数的内存地址,那么将
test1(bar)的返回值赋值给bar,然后,调用bar()的代码完全不用修改!import time
def test_time(func):
def deco():
start_time = time.time()
func()
stop_time = time.time()
print('函数的运行时间是%s'%(stop_time - start_time))
return deco
def bar():
time.sleep(3)
bar = test_time(bar) #把deco的内存地址返回给 bar
bar()
运行结果:
in the bar
函数的运行时间是3.000171661376953
函数test_time 其实就是一个装饰器,它把真正的业务方法func包裹在函数里面,看起来就像是bar被test_time装饰了
如果我们想偷懒不适用赋值语句bar = test_time(bar) ,那么我们就可以用到装饰器的语法糖@,语法糖的意思就是一种语法的简写
,他可以使代码看起来更加简洁,上面的bar = test_time(bar) 和@test_time 然后调用bar()效果是一样的。
import time
def test_time(func):
def deco():
start_time = time.time()
func()
stop_time = time.time()
print('函数的运行时间是%s'%(stop_time - start_time))
return deco
@test_time
def bar():
time.sleep(3)
print('in the bar')
运行的结果和上面一样
这样我们就提高了程序的可重复利用性,当其他函数需要调用装饰器时,可以直接调用。装饰器在python使用非常方便,这得益于python的函数
能够像朋友同的对象一样作为参数传递给其他函数,可以赋值给其他变量,可以作为返回值,被定义在另一个函数内。
如果装饰的函数带有参数,因为你也不知道被装饰的函数会传什么参数,所以可以使用可变参数和关键字参数来接收所有的参数,代码如下:
def test_time(func):
def deco(*args,**kwargs):
start_time = time.time()
func(*args,**kwargs)
stop_time = time.time()
print('函数的运行时间%s'%(stop_time - start_time))
return deco
@test_time
def test2(name,age):
time.sleep(2)
print('in the test2',name,age)
test2('niuhanyang',18)
运行结果:
in the test2: niuniu 18
the func run time is 2.0001144409179688
下面再用装饰器写一个实例,判断用户是否登录,判断的逻辑是这样,运行程序,打印菜单,如果是选择后台管理和添加商品,
就判断用户是否登录,如果没有登陆的话,让用户登陆,如果是查看商品就不需要登陆。
import time,json
def read_file(filename):
with open(filename) as fr:
res = json.load(fr)
return res
login_name = None
def auth(func):
dec(*args,**kwargs):
global login_name
if login_name:
res = func(*args,**kwargs)
return res
else:
user_dic = read_file('users.json')
count = 0
while count <3:
username = input('请输入用户名:').strip()
password = input('请输入密码:').strip()
if username !='' and password ! ='':
if username in user_dic:
if user_dic[username]['password'] = passsword
login_name =username
res = func(*args,**kwargs)
return res
else:
print('密码不正确!!!')
count +=1
else:
print('用户名不存在!!!')
count +=1
else:
print('用户名和密码都不能为空')
cout+ =1
return dec
下面是事先写好的uses.json
{
"admin": {
"password": "123456",
"cart": [
"mac",
"iphone"
]
},
"duguanglong": {
"password": "123456",
"cart": []
}
}
匿名函数
如果这个函数只需要执行一次,那就定义一个匿名函数,匿名函数只能处理比较简单的处理逻辑,只能写简单的表达式,不能写循环判断,比如三元运算符。
匿名函数使用lambda关键字,比如说要定义一个函数,它的功能是要返回两个数字相加,那就可以使用lambda,代码如下:
s = lambda x,y:x+y #冒号前面的x,y是入参,冒号后面的是返回值
print(s(1,9)) #因为函数即变量,如果没有顶一个变量把lambda存起来的话,他就不在内存里,就没有办法执行,所以把它放到s这个变量里面
s(1,9)
运行结果:10
fpython-笔记(五)装饰器、匿名函数的更多相关文章
- python学习笔记(五):装饰器、生成器、内置函数、json
一.装饰器 装饰器,这个器就是函数的意思,连起来,就是装饰函数,装饰器本身也是一个函数,它的作用是用来给其他函数添加新功能,比如说,我以前写了很多代码,系统已经上线了,但是性能比较不好,现在想把程序里 ...
- 20.python笔记之装饰器
装饰器 装饰器是函数,只不过该函数可以具有特殊的含义,装饰器用来装饰函数或类,使用装饰器可以在函数执行前和执行后添加相应操作. 装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插 ...
- python笔记 - day4-之装饰器
python笔记 - day4-之装饰器 需求: 给f1~f100增加个log: def outer(): #定义增加的log print("log") ...
- muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor
目录 muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor Connector 系统函数connect 处理非阻塞connect的步骤: Connetor时序图 Accep ...
- Python学习笔记012——装饰器
1 装饰器 1.1装饰器定义 在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator). 1.2 装饰器分类 装饰器:函数装饰器,类装饰器,函数的装饰器,类的装饰器 装饰器:函数装饰函 ...
- python学习笔记之装饰器、递归、算法(第四天)
参考老师的博客: 金角:http://www.cnblogs.com/alex3714/articles/5161349.html 银角:http://www.cnblogs.com/wupeiqi/ ...
- Day11 Python基础之装饰器(高级函数)(九)
在python中,装饰器.生成器和迭代器是特别重要的高级函数 https://www.cnblogs.com/yuanchenqi/articles/5830025.html 装饰器 1.如果说装 ...
- python:带参数的装饰器,函数的有用信息
一.带参数的装饰器,函数的有用信息 def func1(): '''此函数的功能是完成的登陆的功能 return: 返回值是登陆成功与否(true,false) ''' print(333) func ...
- 关于Python装饰器内层函数为什么要return目标函数的一些个人见解
https://blog.csdn.net/try_test_python/article/details/80802199 前几天在学装饰器的时候,关于装饰器内层函数调用目标函数时是否return目 ...
- diango中让装了装饰器的函数的名字不是inner,而是原来的名字
让装了装饰器的函数的名字不是inner,而是原来的名字 from functools import wraps def wrapper(func): @wraps(func) # 复制了原来函数的名字 ...
随机推荐
- P3158 [CQOI2011]放棋子(dp+组合数)
P3158 [CQOI2011]放棋子 放棋子的顺序和方案数无关,所以可以从按颜色递推 设$f[u][p][k]$为放到第$u$种颜色,所剩空间$p*k$的方案数 $g[u][i][j]$表示第$u$ ...
- sql 字符串 切割函数 FUN_Split
IF EXISTS ( SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FUN_Split]') AND OBJECTPROPER ...
- OD消息断点
[文章作者]: icefisher[作者邮箱]: 181712814@qq.com[软件下载]: [软件名称]: echap518.exe(只是供学习的crackme)[加壳方式]: 里面直接有个un ...
- html常用标签、包含关系、常用术语,以及网页设计中的字体分类
编程比较舒适的等宽字体:DejaVu Sans Mono 字体的分类: serif (衬线字体){在笔画上面有些特殊的修饰效果} sans-serif (非衬线字体){横平竖直.横就是横,点就是点} ...
- VB.net删除节点,数据库,文件
Private Sub mnuDel_Click()'删除节点Dim sKey As String'Dim sFile As StringDim oFS As FileSystemObjectDim ...
- Django【第4篇】:Django之模板继承
jango框架之模板继承和静态文件配置 一.模板继承 目的是:减少代码的冗余 语法: {% block classinfo %} {% endblock %} 具体步骤: 1.创建一个base.htm ...
- 设计模式Design Pattern(1)--简介
什么是设计模式? 软件开发人员在长期实践中总结出来的解决特定问题的一套解决方案. 对象设计原则 计模式主要是基于以下的面向对象设计原则. 对接口编程而不是对实现编程. 优先使用对象组合而不是继承. 设 ...
- note 2019.12.16
1.无序 HTML 列表: <ul> <li>Coffee</li> <li>Tea</li> <li>Milk</li& ...
- java 如何实现大文件上传下载(传输)各种格式
我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用. 首先我们需要了解的是上传文件三要素: 1.表单提交方式:post (get方式提交有大小 ...
- 最大流 && 最小费用最大流模板
模板从 这里 搬运,链接博客还有很多网络流题集题解参考. 最大流模板 ( 可处理重边 ) ; const int INF = 0x3f3f3f3f; struct Edge { int from ...