一、装饰器

装饰器,这个器就是函数的意思,连起来,就是装饰函数,装饰器本身也是一个函数,它的作用是用来给其他函数添加新功能,比如说,我以前写了很多代码,系统已经上线了,但是性能比较不好,现在想把程序里面每个函数都加一个功能,用来统计每个函数的运行时间是多少,找出来运行比较慢的函数,来优化代码,或者一个功能在调用之前必须登陆,就需要添加一个新的功能,来统计程序的运行时间,那这样的话,就得修改每个函数了,需要改代码,但是代码特别多,改完了公司倒闭了,这时候装饰器就能排上用场了,它可以不改变原有的函数,原来的函数和原来一模一样,什么都不需要改变,只需要在函数外部加上调用哪个装饰器就可以了。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-笔记(五)装饰器、匿名函数的更多相关文章

  1. python学习笔记(五):装饰器、生成器、内置函数、json

    一.装饰器 装饰器,这个器就是函数的意思,连起来,就是装饰函数,装饰器本身也是一个函数,它的作用是用来给其他函数添加新功能,比如说,我以前写了很多代码,系统已经上线了,但是性能比较不好,现在想把程序里 ...

  2. 20.python笔记之装饰器

    装饰器 装饰器是函数,只不过该函数可以具有特殊的含义,装饰器用来装饰函数或类,使用装饰器可以在函数执行前和执行后添加相应操作. 装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插 ...

  3. python笔记 - day4-之装饰器

                 python笔记 - day4-之装饰器 需求: 给f1~f100增加个log: def outer(): #定义增加的log print("log") ...

  4. muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor

    目录 muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor Connector 系统函数connect 处理非阻塞connect的步骤: Connetor时序图 Accep ...

  5. Python学习笔记012——装饰器

    1 装饰器 1.1装饰器定义 在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator). 1.2 装饰器分类 装饰器:函数装饰器,类装饰器,函数的装饰器,类的装饰器 装饰器:函数装饰函 ...

  6. python学习笔记之装饰器、递归、算法(第四天)

    参考老师的博客: 金角:http://www.cnblogs.com/alex3714/articles/5161349.html 银角:http://www.cnblogs.com/wupeiqi/ ...

  7. Day11 Python基础之装饰器(高级函数)(九)

    在python中,装饰器.生成器和迭代器是特别重要的高级函数   https://www.cnblogs.com/yuanchenqi/articles/5830025.html 装饰器 1.如果说装 ...

  8. python:带参数的装饰器,函数的有用信息

    一.带参数的装饰器,函数的有用信息 def func1(): '''此函数的功能是完成的登陆的功能 return: 返回值是登陆成功与否(true,false) ''' print(333) func ...

  9. 关于Python装饰器内层函数为什么要return目标函数的一些个人见解

    https://blog.csdn.net/try_test_python/article/details/80802199 前几天在学装饰器的时候,关于装饰器内层函数调用目标函数时是否return目 ...

  10. diango中让装了装饰器的函数的名字不是inner,而是原来的名字

    让装了装饰器的函数的名字不是inner,而是原来的名字 from functools import wraps def wrapper(func): @wraps(func) # 复制了原来函数的名字 ...

随机推荐

  1. ELK-全文检索技术-elasticsearch集群及sde_restful

    1       搭建ES集群 集群的说明 我们计划集群名称为:leyou-elastic,部署3个elasticsearch节点,分别是: node-01:http端口9201,TCP端口9301 n ...

  2. vue filters过滤

    <template> <div class="filters"> <h1 v-text="filtersTitle">< ...

  3. 34. Find First and Last Position of Element in Sorted Array (JAVA)

    Given an array of integers nums sorted in ascending order, find the starting and ending position of ...

  4. django基础篇04-自定义simple_tag和fitler

    自定义simple_tag app目录下创建templatetags目录 templatetags目录下创建xxpp.py 创建template对象register,注意变量名必须为register ...

  5. hdu 1087 最大递增子序列和

    #include <bits/stdc++.h> #define PI acos(-1.0) #define mem(a,b) memset((a),b,sizeof(a)) #defin ...

  6. git分支管理与tag的学习笔记

    git分支管理学习笔记:创建dev分支:git branch dev查看分支:git branch切换分支:git checkout dev创建并切换分支:git checkout dev -b zh ...

  7. C语言realpath

    表头文件:     #include <limits.h>     #include <stdlib.h> 函数原型:     char *realpath(const cha ...

  8. BAT面试必问题系列:深入详解JVM 内存区域及内存溢出分析

    前言 在JVM的管控下,Java程序员不再需要管理内存的分配与释放,这和在C和C++的世界是完全不一样的.所以,在JVM的帮助下,Java程序员很少会关注内存泄露和内存溢出的问题.但是,一旦JVM发生 ...

  9. 在浏览器下载pdf,或者txt文档是会直接打开

    window.location.href = url会直接打开,解释大概是因为浏览器自身可以解析.pdf或者txt.解决方法如下: 本来就要用a标签里面加上download属性的,结果发现不行,就算了 ...

  10. R语言-变量命名规则

    1.大原则:只有字母(区分大小写).数字.“_”(下划线).“.”(英文句号)可以出现. 2.数字.下划线不能开头. 3.英文句号开头不能紧接数字. 就这么简单!