20.python笔记之装饰器
装饰器
装饰器是函数,只不过该函数可以具有特殊的含义,装饰器用来装饰函数或类,使用装饰器可以在函数执行前和执行后添加相应操作。
装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
例:如果一个公司有运维部,开发部,测试部,设计部,等,并且公司具有基础平台架构,为公司各个部门提供数据库调用,资料查看,监控等。当这些部门想使用这些功能的时候,直接调用这些功能的接口就可以,如下:
基础平台提供的功能------------
def 功能1()
print ('功能1')
def 功能2()
print ('功能2')
def 功能3()
print ('功能3')
def 功能4()
print ('功能4')
当运维部门调用的时候如下:
def 功能1()
def 功能2()
def 功能3()
当开发部门调用的时候如下:
def 功能1()
def 功能2()
def 功能3()
之后要为平台提供的所有功能添加验证机制,
基础平台提供如下功能接口:
1.让各个部门修改自己的代码
2.在每个部门实现的功能上加上代码
3.把验证代码变成函数 在每个功能上加入
4.为了追寻开放封闭原则
利用装饰器的功能实现
def login(func):
def inner():
# 验证1
# 验证2
# 验证3
return func()
return inner
@login
def 功能1():
print ('功能1')
@login
def 功能2():
print ('功能2')
@login
def 功能3():
print ('功能3')
@login
def 功能4():
print ('功能4')
当各个部门执行def功能的时候
def login(func):
def inner():
# 验证1
return func()
return inner
@login
def 功能1():
print '功能1'
当调用功能1的时候 会先把功能1的函数名带入内存地址,之后会执行login函数,func为功能1,之后inner会将功能1的参数带入等待执行inner的验证功能后,会将参数交给func执行功能1的命令。
例:
第一步:最简单的函数,准备附加额外功能
def myfunc():
print("调用myfunc().")
myfunc()
myfunc()
结果:
调用myfunc().
调用myfunc().
第二步:使用装饰函数在函数执行前和执行后分别附加额外功能
def deco(func):
print("执行装饰器函数1")
func() #将func的内存地址执行
print("执行装饰器函数2")
return func #返回函数
def myfunc():
print(" 执行myfunc函数")
#执行deco函数的时候会把myfunc函数的内存地址带入
myfunc = deco(myfunc)
print(myfunc)
结果:
执行装饰器函数1
执行myfunc函数
执行装饰器函数2
<function myfunc at 0x0000000000BDA6A8>
第三步:使用语法糖@来装饰函数
def deco(func):
print("装饰器开始")
func()
print("装饰器结束")
return func
@deco
def myfunc():
print("我只是一个普通的函数")
或者:
def deco(func):
user = input('user:')
passwd = input('pass:')
print('验证成功')
func()
return func
#注func函数就是myfunc函数 当装饰器全部执行之后再执行func函数
@deco
def myfunc():
print("欢迎使用京猫平台")
第四步:使用内嵌包装函数来确保每次新函数都被调用
#内嵌包装函数的形参和返回值与原函数相同,装饰函数返回内嵌包装函数对象'''
def deco(func):
def _deco():
user = input('user:')
passwd = input('pass')
print('用户和密码正确')
func()
# 不需要返回func,实际上应返回原函数的返回值
return _deco
@deco
def login():
print("登录成功")
return 'ok'
#login函数可以重复调用多次,每次调用的时候,都会先执行装饰器里的函数,
login()
第五步:对带参数的函数进行装饰
#内嵌包装函数的形参和返回值与原函数相同,装饰函数返回内嵌包装函数对象'''
def deco(func):
def _deco(a, b):
ret = func(a, b)
return ret
return _deco
@deco
def myfunc(a, b):
print(" 函数%s+%s." % (a, b))
return a + b
myfunc(1, 2)
myfunc(3, 4)
#当我执行myfunc带参数的时候调用装饰器函数
第六步:对参数数量不确定的函数进行装饰
#参数用(*args, **kwargs),自动适应变参和命名参数'''
def deco(func):
def _deco(*args, **kwargs): #*agrs和**kwargs是普通函数的参数
print("普通函数名:%s" % func.__name__)
#执行普通函数
ret = func(*args, **kwargs)
print("普通函数%s执行结果为%s" % (func.__name__, ret))
return ret
return _deco
@deco
def myfunc(a, b):
print("普通函数1%s+%s" % (a, b))
return a+b
@deco
def myfunc2(a, b, c):
print("普通函数2%s+%s+%s" % (a, b, c))
return a+b+c
myfunc(1, 2)
myfunc(3, 4)
myfunc2(1, 2, 3)
myfunc2(3, 4, 5)
**第七步:让装饰器带参数**
#装饰函数名实际上应更有意义些'''
def deco(arg):
def _deco(func):
def __deco():
print("普通函数名 %s 装饰器参数名 [%s]." % (func.__name__, arg))
func()
print("普通函数名 %s 装饰器参数名 [%s]." % (func.__name__, arg))
return __deco
return _deco
@deco("装饰器参数1")
def myfunc():
print("普通函数1")
@deco("装饰器参数2")
def myfunc2():
print("普通函数2")
myfunc()
myfunc2()
第八步:装饰器带 类 参数
class locker:
def __init__(self):
print("这个是.__init__().")
@staticmethod
def acquire():
print("(这是静态方法)")
@staticmethod
def release():
print("(不需要对象实例)")
def deco(cls):
'''cls 必须实现acquire和release静态方法'''
def _deco(func):
def __deco():
print("函数名: %s 类:[%s]." % (func.__name__, cls))
cls.acquire()
try:
return func()
finally:
cls.release()
return __deco
return _deco
@deco(locker)
def myfunc():
print("普通函数")
myfunc()
**第九步:装饰器带类参数,并分拆公共类到其他py文件中,同时演示了对一个函数应用多个装饰器**
1.melocker.py(公共类文件)
class mylocker:
def __init__(self):
print("mylocker.__init__() called.")
@staticmethod
def acquire():
print("mylocker.acquire() called.")
@staticmethod
def unlock():
print(" mylocker.unlock() called.")
class lockerex(mylocker):
@staticmethod
def acquire():
print("lockerex.acquire() called.")
@staticmethod
def unlock():
print(" lockerex.unlock() called.")
def lockhelper(cls):
'''cls 必须实现acquire和release静态方法'''
def _deco(func):
def __deco(*args, **kwargs):
print("before %s called." % func.__name__)
cls.acquire()
try:
return func(*args, **kwargs)
finally:
cls.unlock()
return __deco
return _deco
2.使用装饰器文件
#!/usr/bin/env python3
#coding:utf8
from melocker import *
class example:
@lockhelpermelocker)
def myfunc(self):
print(" myfunc() called.")
@lockhelper(melocker)
@lockhelper(lockerex)
def myfunc2(self, a, b):
print(" myfunc2() called.")
return a + b
if __name__=="__main__":
a = example()
a.myfunc()
print(a.myfunc())
print(a.myfunc2(1, 2))
print(a.myfunc2(3, 4))
完毕!!!
20.python笔记之装饰器的更多相关文章
- python笔记 - day4-之装饰器
python笔记 - day4-之装饰器 需求: 给f1~f100增加个log: def outer(): #定义增加的log print("log") ...
- Python笔记:装饰器
装饰器 1.特点:装饰器的作用就是为已存在的对象添加额外的功能,特点在于不用改变原先的代码即可扩展功能: 2.使用:装饰器其实也是一个函数,加上@符号后放在另一个函数“头上”就实现了装饰 ...
- Python学习笔记:装饰器
Python 装饰器的基本概念和应用 代码编写要遵循开放封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即: 封闭:已 ...
- Noah的学习笔记之Python篇:装饰器
Noah的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 3.命令行解析 注:本文全原创,作者:Noah Zhang (http://www.cnblogs.com/noahzn/) ...
- 第二篇:python高级之装饰器
python高级之装饰器 python高级之装饰器 本节内容 高阶函数 嵌套函数及闭包 装饰器 装饰器带参数 装饰器的嵌套 functools.wraps模块 递归函数被装饰 1.高阶函数 高阶函 ...
- Day11 Python基础之装饰器(高级函数)(九)
在python中,装饰器.生成器和迭代器是特别重要的高级函数 https://www.cnblogs.com/yuanchenqi/articles/5830025.html 装饰器 1.如果说装 ...
- 十. Python基础(10)--装饰器
十. Python基础(10)--装饰器 1 ● 装饰器 A decorator is a function that take a function as an argument and retur ...
- Python核心编程 | 装饰器
装饰器是程序开发的基础知识,用好装饰器,在程序开发中能够提高效率 它可以在不需要修改每个函数内部代码的情况下,为多个函数添加附加功能,如权限验证,log日志等 涉及点: 1.先梳理一下 ...
- 写python中的装饰器
python中的装饰器主要用于在已有函数实现功能前附加需要输出的信息,下面将用实例展示我如何写装饰器. 首先分别尝试写装饰器装饰一个无参函数和一个有参函数(被装饰函数仅输出,无返回值情况下) def ...
随机推荐
- javaEE规范和SSH三大框架到底有什么关系
转自博客:http://blog.csdn.net/bingjing12345/article/details/20641891 1994-2000 年是互联网的大航海时代. 请注意,下面的时间点及其 ...
- iOS-编译简单静态库初探
首先声明,我写的这些网上都有更详细的内容,在这里只是写下我自己总结的一些重要内容,具体步骤如下: 事先准备:新建工程-Framework & Library - Cocoa Touch Sta ...
- Blog Explanation
有疑问或blog中说明错误的欢迎评论或联系QQ:30056882,邮箱BLADEVIL@outlook.com.本人水平不高,欢迎讨论问题. blog中所有随笔均为原创,转载请注明来源. (已退役.)
- 手动搭建SpringMVC报错
猜测这个是由于自己在搭建时缺少包造成的,后来将按照自己之前的项目将包补齐,tomcat就不报错了,看来还是要学习maven 这样就不会缺少包了
- TortoiseSVN客户端如何更改新的URL
问题: 我们的服务器换了新的URL地址,这时候我们本地的SVN访问帐号和地址就要重新定义了. 解决步骤: 1:重新定义SVN的URL,右键(TortoiseSVN) → Relocate → 输入你新 ...
- 关于mysql乱码的问题
ALTER TABLE TABLE_NAME CONVERT TO CHARACTER SET utf8 COLLATE UTF8_GENERAL_CI; 第一步,用mysql的自带修复工具在bin文 ...
- 配置Junit测试程序
第一步:加载所需要的包:右键-->Build Path-->Configure Build Path-->Libraries-->Add Library-->Junit ...
- node相关的精典材料
node.js电子书 了不起的Node.js 深入浅出Node.js node.js入门经典 node.js开发指南 node.js相关优秀博文 官网 Infoq深入浅出Node.js系列(进阶必读) ...
- 优秀大数据GitHub项目一览
http://blog.csdn.net/yaoxtao/article/details/50540485 优秀大数据GitHub项目一览 VMware CEO Pat Gelsinger曾说: 数据 ...
- jgestures 一款jquery手势插件
jgestures插件允许你如同原生的jQuery事件一样监听以下事件:'pinch'(缩放手势), 'rotate'(旋转手势), 'swipe'(滑动手势), 'tap'(轻触) 以及 'orie ...