装饰器

装饰器是函数,只不过该函数可以具有特殊的含义,装饰器用来装饰函数或类,使用装饰器可以在函数执行前和执行后添加相应操作。

装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

例:如果一个公司有运维部,开发部,测试部,设计部,等,并且公司具有基础平台架构,为公司各个部门提供数据库调用,资料查看,监控等。当这些部门想使用这些功能的时候,直接调用这些功能的接口就可以,如下:

基础平台提供的功能------------

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笔记之装饰器的更多相关文章

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

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

  2. Python笔记:装饰器

    装饰器        1.特点:装饰器的作用就是为已存在的对象添加额外的功能,特点在于不用改变原先的代码即可扩展功能: 2.使用:装饰器其实也是一个函数,加上@符号后放在另一个函数“头上”就实现了装饰 ...

  3. Python学习笔记:装饰器

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

  4. Noah的学习笔记之Python篇:装饰器

    Noah的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 3.命令行解析 注:本文全原创,作者:Noah Zhang  (http://www.cnblogs.com/noahzn/) ...

  5. 第二篇:python高级之装饰器

    python高级之装饰器   python高级之装饰器 本节内容 高阶函数 嵌套函数及闭包 装饰器 装饰器带参数 装饰器的嵌套 functools.wraps模块 递归函数被装饰 1.高阶函数 高阶函 ...

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

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

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

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

  8. Python核心编程 | 装饰器

        装饰器是程序开发的基础知识,用好装饰器,在程序开发中能够提高效率 它可以在不需要修改每个函数内部代码的情况下,为多个函数添加附加功能,如权限验证,log日志等   涉及点:   1.先梳理一下 ...

  9. 写python中的装饰器

    python中的装饰器主要用于在已有函数实现功能前附加需要输出的信息,下面将用实例展示我如何写装饰器. 首先分别尝试写装饰器装饰一个无参函数和一个有参函数(被装饰函数仅输出,无返回值情况下) def ...

随机推荐

  1. Android中获取图片的宽和高

    在Android中,我们想获取图片的宽和高应该怎么办?一.正常加载图片的方法下获取宽和高 举一个简单的例子:创建一个图片的副本 //加载原图 Bitmap bmSrc = BitmapFactory. ...

  2. BZOJ-3130 费用流 (听题目胡扯丶裸最大流) 二分判定+最大流+实数精度乱搞

    DCrusher爷喜欢A我做的水题,没办法,只能A他做不动的题了.... 3130: [Sdoi2013]费用流 Time Limit: 10 Sec Memory Limit: 128 MBSec ...

  3. POJ 2828 Buy Tickets

    Description Railway tickets were difficult to buy around the Lunar New Year in China, so we must get ...

  4. 一个完整的编译器前端-A.1 源语言

    这个语言的一个程序由一个块组成,该块中包含可选的声明和语句.语法符号basic表示基本类型. program –> block block   –> { decls stmts } dec ...

  5. 使用multi curl进行http并发访问

    curl是一款利用URL语法进行文件传输的工具,它支持多种协议,包括FTP, FTPS, HTTP, HTTPS, GOPHER, TELNET等,我们既可以在命令行上使用它,也可以利用 libcur ...

  6. CSS3系列三(与背景边框相关样式 、变形处理、动画效果)

    与背景相关的新增属性 大家都知道在HTML页面中,元素都是由以下几部分组成 使用background-clip来修改背景的显示范围,如果设定为border-box,则背景范围包含边框区域,如果设定为p ...

  7. yum被锁Another app is currently holding the yum lock; waiting for it to exit...

    可能是系统自动升级正在运行,yum在锁定状态中. 可以通过强制关掉yum进程: #rm -f /var/run/yum.pid 然后就可以使用yum了.

  8. 登陆后淡入淡出更换rootViewController

    - (void)restoreRootViewController:(UIViewController *)rootViewController { typedef void (^Animation) ...

  9. int(11)最大长度是多少,MySQL中varchar最大长度是多少(转)

    int(11)最大长度是多少,MySQL中varchar最大长度是多少? int(11)最大长度是多少? 在SQL语句中int代表你要创建字段的类型,int代表整型,11代表字段的长度. 这个11代表 ...

  10. struts+spring action应配置为scope="prototype"

    truts+spring action应配置为scope="prototype" <bean id="personAction" scope=" ...