1.装饰器

  首先我们来说一下一个软件的设计原则:开闭原则,又被称为开发封闭原则,你的代码对功能的扩展是开放的,你的程序对修改源代码是封闭的.这样的软件设计思路可以更好的维护和开发.

  开放:对功能扩展开放

  封闭:对修改代码封闭

  接下来我们看装饰器.首先我们先模拟一下女娲造人.

def  create():
print('女娲很厉害,捏个泥人吹口气就成了人') create_people()

  现在我们让这个函数加个浇水功能.

def  create():
print('浇水')
print('女娲很厉害,捏个泥人吹口气就成了人') create_people()

  但是,现在就违反了开闭原则,如果每次要添加新功能,那这样就等于是修改了源代码.因为开闭原则对修改是封闭的,那怎么办,我们可以这样做

def water():
print('先浇水')
create()
water()

  这样做的问题是.函数写好了,重新创建了这个函数,在这之前访问过这个函数的人必须要修改代码来访问新的函数water(),所以现在就用到了装饰器,装饰器的作用就是在不修改原有代码的基础上,给函数扩展功能

def create_people():
print('女娲很厉害随随便便就造人')
def water(fn):
def inner():
print('浇浇水')
fn()
print('施肥')
return inner # # create_people() # 这个就不行了.
# warter() # 访问浇水就好了 # func = water(create_people)
# func() # 有人问了. 下游访问的不不依然是func么, 不不还是要改么?
create_people = water(create_people)
create_people() # 这回就好了吧

 说一下执行流程:

结论: 我们使用water函数把create_people给包装了一下. 在不修改create_people的前提下.
完成了对create_people函数的功能添加

下面我们给出装饰器的完整模型代码

def wrapper(fn):  # fn是目标函数
def inner(*args,**kwargs): # 为了目标函数的传参
'''这里是执行函数前的内容'''
ret = fn(*args,**kwargs) # 调用目标函数,ret是目标函数的返回值
'''这里是执行目标函数后的内容
return ret # 把目标函数的返回值返回.保证函数正常的结束
return inner @wrapper # 这里是语法糖
def func():
print('我是目标函数") func() # 调用目标函数

  

二.带参数的装饰器

  注意: 咱们之前的写法是@wrapper 其中wrapper是一个函数. 那么也就是说. 如果我能让wrapper这里换成个函数就行了了. wrapper(True)返回的结果是wrapper也是⼀一个函数啊. 刚刚

好和前面的@组合成一个@wrapper. 依然还是原来那个装饰器. 只不过这里套了3层. 但你要
能看懂. 其实还是原来那个装饰器@wrapper

  

  执行步骤:    

    先执行wrapper(True) 然后再@返回值. 返回值恰好是wrapper. 结果就是@wrapper

下面是装饰器传参的通用写法

def wrapper_out(flag):
def wrapper(fn):
def inner(*args,**kwargs):
if flag == True:
'''执行目标函数前的位置'''
ret = fn(*args,**kwargs)
'''执行目标函数后的位置'''
return ret
else:
ret = fn(*args,**args)
return ret
return inner
return wrapper @wrapper_out(True)
def func():
print('这里是目标函数') func()

  

三.多个装饰器装饰同一个函数

def wrapper1(fn):
def inner(*args,**kwargs):
print('111')
ret = fn(*args,**kwargs)
print('222')
return inner def wrapper2(fn):
def inner(*args,**kwargs):
print('333')
ret = fn(*args,**kwargs)
print('444')
return inner def wrapper3(fn):
def inner(*args,**kwargs):
print('555')
ret = fn(*args,**kwargs)
print('666')
return inner @wrapper1
@wrapper2
@wrapper3
def eat():
print('我想吃水果') eat()

  

  执行顺序: 首先@wrapper1装饰起来. 然后获取到⼀个新函数是wrapper1中的inner. 然后执行@wrapper2.这个时候. wrapper2装饰的就是wrapper1中的inner了了. 所以. 执行顺序就像:第⼆层装饰器前(第⼀层装饰器前(目标)第一层装饰器后)第二层装饰器后. 程序从左到右执行起来. 就是我们看到的结果

 

四.  使用wraps装饰函数保留函数的原名称

1.wraps

装饰器装饰的函数名字会变为inner,为了让装饰的函数名还原,我们用到了@wraps,这样打印出的函数名就还是原来的函数名了, 要引入functools模块

from functools import wraps # 可以改变一个函数的名字, 注释...

def wrapper(fn):
@wraps(fn) # 把inner的名字改变成原来的func
def inner(*args, **kwargs):
print("前")
ret = fn(*args, **kwargs)
print("后")
return ret return inner @wrapper # func = wrapper(func)
def func():
print('哈哈哈') print(func.__name__) # func

  

python当中的装饰器的更多相关文章

  1. 面向切面编程AOP——加锁、cache、logging、trace、同步等这些较通用的操作,如果都写一个类,则每个用到这些功能的类使用多继承非常难看,AOP就是解决这个问题的,python AOP就是装饰器

    面向切面编程(AOP)是一种编程思想,与OOP并不矛盾,只是它们的关注点相同.面向对象的目的在于抽象和管理,而面向切面的目的在于解耦和复用. 举两个大家都接触过的AOP的例子: 1)java中myba ...

  2. python高级之装饰器

    python高级之装饰器 本节内容 高阶函数 嵌套函数及闭包 装饰器 装饰器带参数 装饰器的嵌套 functools.wraps模块 递归函数被装饰 1.高阶函数 高阶函数的定义: 满足下面两个条件之 ...

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

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

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

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

  5. Python深入05 装饰器

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 装饰器(decorator)是一种高级Python语法.装饰器可以对一个函数.方法 ...

  6. Day04 - Python 迭代器、装饰器、软件开发规范

    1. 列表生成式 实现对列表中每个数值都加一 第一种,使用for循环,取列表中的值,值加一后,添加到一空列表中,并将新列表赋值给原列表 >>> a = [0, 1, 2, 3, 4, ...

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

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

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

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

  9. 简单说明Python中的装饰器的用法

    简单说明Python中的装饰器的用法 这篇文章主要简单说明了Python中的装饰器的用法,装饰器在Python的进阶学习中非常重要,示例代码基于Python2.x,需要的朋友可以参考下   装饰器对与 ...

随机推荐

  1. Drools5

    参考:https://wenku.baidu.com/view/a6516373f242336c1eb95e7c.html   (比较好的 但是是drl 原生的) 参考2:http://asialee ...

  2. 发布spring jar包, 报错

    org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Una ...

  3. 迷你MVVM框架 avalonjs 学习教程2、模块化、ViewModel、作用域

    一个项目是由许多人分工写的,因此必须要合理地拆散,于是有了模块化.体现在工作上,PM通常它这为某某版块,某某频道,某某页面.某一个模块,必须是包含其固有的数据,样式,HTML与处理逻辑.在jQuery ...

  4. 使用Visual Studio进行 Android开发的十大理由

    [原文发表地址]Top 10 reasons to use Visual Studio for C++ Android Development! Visual Studio: C++跨平台的移动解决方 ...

  5. input实时监听控制输入框的输入内容和长度,并进行提示和反馈

    一.前言 在MVVM模式下,有个双向数据绑定(data-binding)的优势,可以通过viewmodel实时的监听用户操作,也可以将model的改动实时的反馈到界面上. 那么,在传统的js操控DOM ...

  6. 外层div高度不随内层div高度改变的解决办法

    当b1和b2都是float=left时候,a1层的高度不会被b1和b2的高度撑开. <div id=“div1″> <div id=”div2″ style="float: ...

  7. jQuery validator 增加多个模板

    今天学了jquery validator 可以增加多个模板,而不用写长长的js代码.废话少说,直接上例子 这段是要添加的模板 上面是把模板部分是要重复增加多个的部分,需独立出来,用textarea标签 ...

  8. golang之panic,recover,defer

    defer,recover: 运行时恐慌一旦被引发,就会向调用方传播直至程序崩溃. recover内建函数用于“拦截”运行时恐慌,可以使当前的程序从恐慌状态中恢复并重新获得流程控制权. recover ...

  9. [mongoDB] mongoDb

    mongodb memcached redis        kv数据库(key/value) mongodb 文档数据库,存储的是文档(Bson->json的二进制化). 特点:内部执行引擎为 ...

  10. 饮品类App原型制作分享-WineRatingsPlus

    WineRatingsPlus是一款关于红酒的App应用.它帮助你在用餐.聚会或任何场合选择葡萄酒时,都能方便的得到专家意见.同时,它也能帮助鉴赏家和感兴趣的人对葡萄酒更多的了解和选择. 在这款Moc ...