一,什么是装饰器

本质就是函数,功能是为其他函数添加附加功能

原则:

1,不修改被修饰函数的源代码

2,不修改被修饰函数的调用方式

例子:

import time

def timmer(func):
def wapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
stop_time = time.time()
print('函数的运行时间 %s' % (stop_time - start_time))
return res
return wapper @timmer #加装饰器
def cal(l): #原函数
res = 0
time.sleep(1)
for i in l:
res += i
return res t1 = cal(range(100))
print(t1)
'''输出:
函数的运行时间 1.0000572204589844
4950
'''

二,装饰器的知识储备

装饰器 =  高阶函数 + 函数嵌套(闭包)

(一)高阶函数

定义:

1,函数接受的参数是一个函数名

2,函数的返回值是一个函数名

3,满足上述条件任意一个,都可称之为高阶函数

例子:高阶函数

def foo():
print('你好啊林师傅') def test(func):
print(func) #打印内存地址
func() #执行函数foo test(foo) #test是高阶
'''输出:
<function foo at 0x00000000022F22F0>
你好啊林师傅
'''

例子:函数接受的参数是一个函数名,就能实现给函数增加功能的目标

def foo():
time.sleep(3)
print('你好啊林师傅') def test(func):
start_time = time.time()
func() #执行函数foo
stop_time = time.time()
print('函数的运行时间 %s' % (stop_time - start_time)) test(foo) #修改了函数原来的调用方式,原来是foo()
'''输出:
你好啊林师傅
函数的运行时间 3.000171661376953
'''

例子:如果再加上返回值是一个函数,则能实现“不修改被修饰函数的调用方式”这一个条件

def foo():
print('from the foo')
def test(func):
return func # res = test(foo)
# print(res) #res得到的是foo的内存地址
# res() #实际是运行foo
foo = test(foo) #如果把函数的执行结果重新赋值给foo函数名
foo() #就能实现“不修改被修饰函数的调用方式”这一个条件
'''输出:
from the foo
'''

例子:多运行一次,并不合格(高阶函数并不能全部满足装饰器的需要)                1,不修改foo源代码,2,不修改foo调用方式

def foo():
time.sleep(3)
print('from the foo') def timer(func):
start_time = time.time()
func() #执行函数foo
stop_time = time.time()
print('函数的运行时间 %s' % (stop_time - start_time))
return func foo = timer(foo)
foo() #又执行了一次函数foo
'''输出:
from the foo
函数的运行时间 3.007171869277954
from the foo
'''

(二),函数嵌套

定义:在函数里面定义另一个函数

def bar():
print('from bar') def foo():
print('from foo')
def test():
pass

函数闭包:

闭——封装变量,包——层层嵌套。其实和函数作用域是一回事。特性:如果内层没有定义重名变量,外层的变量可以传进来。

def father(auth_type):
# print('from father %s' %name)
def son():
# name='linhaifeng_1'
# print('我的爸爸是%s' %name)
def grandson():
print('我的爷爷是%s' %auth_type)#实参'filedb'从最外层一直传导进来
grandson()
# print(locals())
son()
# father('linhaifeng')
father('filedb') #输出:我的爷爷是filedb

三,装饰器框架

使用高阶函数+函数闭包完成装饰器框架。

个人理解:1,装饰器函数传入的原函数名func,用在最内层运行原函数,以实现和原函数一样的效果

2,而在原函数外层包裹的一层函数wrapper,加retunrn wapper返回的是加入新功能后的一个函数地址,在外面运行这个函数地址也就执行了加入的新功能

3,而@这样一个语法把新函数的地址赋值给原函数名,这样运行原函数名,就把新的功能增加了。

def timmer(func): #func=test
def wrapper():
# print(func)
start_time=time.time()
func() #就是在运行test()
stop_time = time.time()
print('运行时间是%s' %(stop_time-start_time))
return wrapper @timmer #test=timmer(test)
def test():
time.sleep(3)
print('test函数运行完毕')
test()
'''输出:
test函数运行完毕
运行时间是3.000171661376953
''' #先使用res来接收
# res=timmer(test) #返回的是wrapper的地址
# res() #执行的是wrapper() #然后使用test原函数名替换res
# test=timmer(test) #返回的是wrapper的地址
# test() #执行的是wrapper() #最后python提供@语法等效于test=timmer(test)
# @timmer 就相当于 test=timmer(test)

例子:原函数加入返回值情况

import time
def timmer(func):
def wrapper():
start_time=time.time()
res=func() #使用res接收返回值
stop_time = time.time()
print('运行时间是%s' %(stop_time-start_time))
return res #把返回值传回去
return wrapper @timmer
def test():
time.sleep(3)
print('test函数运行完毕')
return '这是test的返回值' #这里原函数test加入了返回值 res=test()
print(res)
'''输出:
test函数运行完毕
运行时间是3.007171869277954
这是test的返回值
'''

例子:加入参数,并且考虑原函数参数不固定的情况

#传参的复习和回顾
def test2(name,age,gender): #test2(*('alex',18,'male','x','y'),**{})
#name,age,gender=('alex',18,'male','x','y')
print(name)
print(age)
print(gender) def test1(*args,**kwargs):
test2(*args,**kwargs) #args=('alex',18,'male','x','y') kwargs={} test1('alex',18,gender='male') #正确的传参方式
test1('alex',18,'male') #正确的传参方式
test1('alex',18,'male','x','y')#多传了两个参数,报错:test2() takes 3 positional arguments but 5 were given
#(*args,**kwargs)实现了传递可变参数的功能,在原函数有多个变体的情况下,装饰器函数可以通用
import time
def timmer(func):
def wrapper(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs) #可以理解为wrapper得到的参数原封不动的传进原函数
print('args 是 %s:' %(args,))
print('kwargs 是: %s' %kwargs)
stop_time = time.time()
print('运行时间是%s' %(stop_time-start_time))
return res
return wrapper @timmer
def test(name,age): #两个参数
time.sleep(1)
print('test函数运行完毕,名字是【%s】 年龄是【%s】' %(name,age))
return '这是test的返回值' @timmer
def test1(name,age,gender): #三个参数
time.sleep(1)
print('test1函数运行完毕,名字是【%s】 年龄是【%s】 性别【%s】' %(name,age,gender))
return '这是test1的返回值' test('linhaifeng',age=18) #args=('linhaifeng') kwargs={'age':18}
print('######')
test1('alex',18,'male') #args=('alex',18,'male') kwargs={} '''输出:
test函数运行完毕,名字是【linhaifeng】 年龄是【18】
args 是 ('linhaifeng',):
kwargs 是: {'age': 18}
运行时间是1.0000572204589844
######
test1函数运行完毕,名字是【alex】 年龄是【18】 性别【male】
args 是 ('alex', 18, 'male'):
kwargs 是: {}
运行时间是1.0000572204589844
'''

两个小技巧

#1,解压序列
a,*_,c =[10,9,8,7,6]#代表所有值
print(a)
print(_) #下划线_是变量
print(c)
'''输出:
10
[9, 8, 7]
6
''' #2,交换两个变量值
f1 = 1
f2 = 10
f1,f2 = f2,f1
print(f1,f2)
#输出:10 1

四,装饰器实战

(一)使用装饰器实现验证和session功能

user_list=[
{'name':'alex','passwd':''},
{'name':'linhaifeng','passwd':''},
{'name':'wupeiqi','passwd':''},
{'name':'yuanhao','passwd':''},
]
current_dic={'username':None,'login':False} def auth_func(func):
def wrapper(*args,**kwargs):
if current_dic['username'] and current_dic['login']:
res = func(*args, **kwargs)
return res
username=input('用户名:').strip()
passwd=input('密码:').strip()
for user_dic in user_list:
if username == user_dic['name'] and passwd == user_dic['passwd']:
current_dic['username']=username
current_dic['login']=True
res = func(*args, **kwargs)
return res
else: #######这个else非常有价值,不是if的else,而是for的else
print('用户名或者密码错误') return wrapper @auth_func
def index():
print('欢迎来到京东主页') @auth_func
def home(name):
print('欢迎回家%s' %name) @auth_func
def shopping_car(name):
print('%s的购物车里有[%s,%s,%s]' %(name,'奶茶','妹妹','娃娃')) print('before-->',current_dic)
index()
print('after--->',current_dic)
home('产品经理')
# shopping_car('产品经理')

五,装饰器运行流程

1,运行@装饰器函数名,实际动作是运行装饰器函数,由于闭包函数wrapper定义在这个装饰器函数的里面,所以仅return wrapper,把wrapper的函数地址返回给原函数名(重新赋值)

2,当程序运行到原函数名(),也就是执行原函数时,因为前面的步骤,实际跳转到wrapper函数执行。这里面巧妙的地方是,wrapper函数里面又包含一个原函数(),这回是真正执行原函数()。

3,执行完原函数后,回到wrapper里面,原函数()下面的步骤运行。

六,带参数的装饰器函数

本质就是在外面再添加一层,把原装饰器函数包裹起来。原装饰器函数实现的是把原函数名传递进去在内层,带参数的装饰器函数实现传递功能性参数作用在最外层,层层嵌套。

user_list=[
{'name':'alex','passwd':''},
{'name':'linhaifeng','passwd':''},
{'name':'wupeiqi','passwd':''},
{'name':'yuanhao','passwd':''},
]
current_dic={'username':None,'login':False} def auth(auth_type='filedb'):
def auth_func(func):
def wrapper(*args,**kwargs):
print('认证类型是',auth_type)
if auth_type == 'filedb':
if current_dic['username'] and current_dic['login']:
res = func(*args, **kwargs)
return res
username=input('用户名:').strip()
passwd=input('密码:').strip()
for user_dic in user_list:
if username == user_dic['name'] and passwd == user_dic['passwd']:
current_dic['username']=username
current_dic['login']=True
res = func(*args, **kwargs)
return res
else:
print('用户名或者密码错误')
elif auth_type == 'ldap':
print('鬼才特么会玩')
res = func(*args, **kwargs)
return res
else:
print('鬼才知道你用的什么认证方式')
res = func(*args, **kwargs)
return res return wrapper
return auth_func @auth(auth_type='filedb') #auth_func=auth(auth_type='filedb')-->@auth_func 附加了一个auth_type --->index=auth_func(index)
def index():
print('欢迎来到京东主页') @auth(auth_type='ldap')
def home(name):
print('欢迎回家%s' %name)
#
@auth(auth_type='sssssss')
def shopping_car(name):
print('%s的购物车里有[%s,%s,%s]' %(name,'奶茶','妹妹','娃娃')) # print('before-->',current_dic)
# index()
# print('after--->',current_dic)
# home('产品经理')
shopping_car('产品经理')

【笔记】Python基础五:装饰器的更多相关文章

  1. python基础—函数装饰器

    python基础-函数装饰器 1.什么是装饰器 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能. 装饰器的返回值是也是一个函数对象. 装饰器经常用于有切 ...

  2. 十. Python基础(10)--装饰器

    十. Python基础(10)--装饰器 1 ● 装饰器 A decorator is a function that take a function as an argument and retur ...

  3. [python基础]关于装饰器

    在面试的时候,被问到装饰器,在用的最多的时候就@classmethod ,@staticmethod,开口胡乱回答想这和C#的static public 关键字是不是一样的,等面试回来一看,哇,原来是 ...

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

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

  5. 1.16 Python基础知识 - 装饰器初识

    Python中的装饰器就是函数,作用就是包装其他函数,为他们起到修饰作用.在不修改源代码的情况下,为这些函数额外添加一些功能,像日志记录,性能测试等.一个函数可以使用多个装饰器,产生的结果与装饰器的位 ...

  6. 学习PYTHON之路, DAY 5 - PYTHON 基础 5 (装饰器,字符格式化,递归,迭代器,生成器)

    ---恢复内容开始--- 一 装饰器 1 单层装饰器 def outer(func): def inner(): print('long') func() print('after') return ...

  7. Python开发【第一篇】Python基础之装饰器

    写代码要遵循开发封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即: 封闭:已实现的功能代码块开放:对扩展开发 #s2 ...

  8. python基础-----函数/装饰器

    函数 在Python中,定义一个函数要使用def语句,依次写出函数名.括号.括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回. 函数的优点之一是,可以将代码块与主程 ...

  9. python基础之装饰器(实例)

    1.必备 #### 第一波 #### def foo(): print 'foo' foo #表示是函数 foo() #表示执行foo函数 #### 第二波 #### def foo(): print ...

  10. 【Python基础】装饰器的解释和用法

    装饰器的用法比较简单,但是理解装饰器的原理还是比较复杂的,考虑到接下来的爬虫框架中很多用到装饰器的地方,我们先来讲解一下. 函数 我们定义了一个函数,没有什么具体操作,只是返回一个固定值 请注意一下缩 ...

随机推荐

  1. CUDA 编程

    作者:MingChaoSun 原文:https://blog.csdn.net/sunmc1204953974/article/details/51000970 一.CPU和GPU 上图是CPU与GP ...

  2. php.ini文件下载

    该php.ini文件为修改版,完美运行,存于360云盘.

  3. JavaScript获取元素CSS计算后的样式

    原文链接https://www.w3ctech.com/topic/40 我们在开发过程中,有时候需要根据元素已有样式来实现一些效果,那我们应该如何通过JavaScript来获取一个元素计算后的样式值 ...

  4. [UE4]镜像

    一.这是一个右手模型,通过镜像可以得到一个左右模型. 二.通过上图分析,镜面是X轴和Z轴形成的一个面,Y轴与XZ面垂直,因此就是镜像Y轴,将模型的Transform.Scale.Y设置为-1,即可得到 ...

  5. Unity Shader Graph(三)Phase In and Out

    软件环境 Unity 2018.1.6f1 Lightweight Render Pipeline 1.1.11-preview Phase In and Out效果预览 角色沿Y轴逐渐出现和消失 S ...

  6. ORA-27302: 错误发生在: sskgpwrm1

    opidrv aborting process M002 ospid (3561) as a result of ORA-600ORA-27300: 操作系统相关操作: semctl 失败, 状态为: ...

  7. Linux7.2 UDEV

    1. 生成规则文件 touch /etc/udev/rules.d/99-oracle-asmdevices.rules 或者 touch /usr/lib/udev/rules.d/99-oracl ...

  8. Android Studio无法识别手机

    1.代理配置 1.1 无FQ的网络:需要配置代理: 1.2 公司网:不需要配置代理: 2.检查驱动安装情况: 2.1 检查设备管理器中的驱动是否正常安装: 成功后: 3.手机开启开发者模式

  9. RN-环境配置

    良好的开端是成功的一半,这是window平台安装步骤 首先配置JDK1.8  配置JAVA_HOME环境变量 然后安装Android Studio3.2 然后安装react-native-cli np ...

  10. C#异步方法

      Task MainTask;   MainTask = Task.Factory.StartNew(() =>             { //耗时的异步逻辑 });