博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python笔记第九天 装饰器
阅读量:6243 次
发布时间:2019-06-22

本文共 5891 字,大约阅读时间需要 19 分钟。

装饰器

装饰器是这样一种设计模式:如果一个类希望添加其他类的一些功能,而不希望通过继承或是直接修改源代码实现,那么可以使用装饰器模式。简单来说Python中的装饰器就是指某些函数或其他可调用对象,以函数或类作为可选输入参数,然后返回函数或类的形式。通过这个在Python2.6版本中被新加入的特性可以用来实现装饰器设计模式。

顺便提一句,在继续阅读之前,如果你对Python中的闭包(Closure)概念不清楚,请查看本文结尾后的附录,如果没有闭包的相关概念,很难恰当的理解Python中的装饰器。

在Python中,装饰器被用于用@语法糖修辞的函数或类。现在让我们用一个简单的装饰器例子来演示如何做一个函数调用日志记录器。在这个例子中,装饰器将时间格式作为输入参数,在调用被这个装饰器装饰的函数时打印出函数调用的时间。这个装饰器当你需要手动比较两个不同算法或实现的效率时很有用。

def logged(time_format):  def decorator(func):   def decorated_func(*args, **kwargs):     print "- Running '%s' on %s " % (                     func.__name__,                     time.strftime(time_format)               )     start_time = time.time()     result = func(*args, **kwargs)     end_time = time.time()     print "- Finished '%s', execution time = %0.3fs " % (                     func.__name__,                     end_time - start_time               )       return result   decorated_func.__name__ = func.__name__   return decorated_func return decorator

这里add1和add2函数被logged修饰,下面给出了一个输出示例。请注意在这里时间格式参数是存储在被返回的装饰器函数中(decorated_func)。这就是为什么理解闭包对于理解装饰器来说很重要的原因。同样也请注意返回函数的名字是如何被替换为原函数名的,以防万一如果它还要被使用到,这是为了防止混淆。

 

@logged("%b %d %Y - %H:%M:%S")def add1(x, y):  time.sleep(1)  return x + y  @logged("%b %d %Y - %H:%M:%S")def add2(x, y):  time.sleep(2)  return x + y  print add1(1, 2)print add2(1, 2)  # Output:- Running 'add1' on Jul 24 2013 - 13:40:47- Finished 'add1', execution time = 1.001s3- Running 'add2' on Jul 24 2013 - 13:40:48- Finished 'add2', execution time = 2.001s

 

以下内容来自http://www.cnblogs.com/luotianshuai/p/4967834.html 

一、初创公司有N个业务部门,1个基础平台部门,基础平台负责提供底层的功能,如:数据库操作、redis调用、监控API等功能。业务部门使用基础功能时,只需调用基础平台提供的功能即可。如下:

 

############### 基础平台提供的功能如下 ###############   def f1():    print 'f1'  def f2():    print 'f2'  def f3():    print 'f3'  def f4():    print 'f4'  ############### 业务部门A 调用基础平台提供的功能 ###############   f1()f2()f3()f4()  ############### 业务部门B 调用基础平台提供的功能 ###############   f1()f2()f3()f4()

 

目前公司有条不紊的进行着,但是,以前基础平台的开发人员在写代码时候没有关注验证相关的问题,即:基础平台的提供的功能可以被任何人使用。现在需要对基础平台的所有功能进行重构,为平台提供的所有功能添加验证机制,即:执行功能前,先进行验证。

老大把工作交给 Low B,他是这么做的:

 

1
跟每个业务部门交涉,每个业务部门自己写代码,调用基础平台的功能之前先验证。诶,这样一来基础平台就不需要做任何修改了。

 

 当天Low B 被开除了...

老大把工作交给 Low BB,他是这么做的

                           
只对基础平台的代码进行重构,让N业务部门无需做任何修改
############### 基础平台提供的功能如下 ############### def f1():    # 验证1    # 验证2    # 验证3    print 'f1'def f2():    # 验证1    # 验证2    # 验证3    print 'f2'def f3():    # 验证1    # 验证2    # 验证3    print 'f3'def f4():    # 验证1    # 验证2    # 验证3    print 'f4'############### 业务部门不变 ############### ### 业务部门A 调用基础平台提供的功能### f1()f2()f3()f4()### 业务部门B 调用基础平台提供的功能 ### f1()f2()f3()f4()

过了一周 Low BB 被开除了...

老大把工作交给 Low BBB,他是这么做的:

只对基础平台的代码进行重构,其他业务部门无需做任何修改
############### 基础平台提供的功能如下 ############### def check_login():    # 验证1    # 验证2    # 验证3    passdef f1():        check_login()    print 'f1'def f2():        check_login()    print 'f2'def f3():        check_login()    print 'f3'def f4():        check_login()        print 'f4'

老大看了下Low BBB 的实现,嘴角漏出了一丝的欣慰的笑,语重心长的跟Low BBB聊了个天:

老大说:

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

  • 封闭:已实现的功能代码块
  • 开放:对扩展开发

如果将开放封闭原则应用在上述需求中,那么就不允许在函数 f1 、f2、f3、f4的内部进行修改代码,老板就给了Low BBB一个实现方案:

 

def w1(func):    def inner():        # 验证1        # 验证2        # 验证3        return func()    return inner  @w1def f1():    print 'f1'@w1def f2():    print 'f2'@w1def f3():    print 'f3'@w1def f4():    print 'f4'

对于上述代码,也是仅仅对基础平台的代码进行修改,就可以实现在其他人调用函数 f1 f2 f3 f4 之前都进行【验证】操作,并且其他业务部门无需做任何操作。

Low BBB心惊胆战的问了下,这段代码的内部执行原理是什么呢?

老大正要生气,突然Low BBB的手机掉到地上,恰恰屏保就是Low BBB的女友照片,老大一看一紧一抖,喜笑颜开,交定了Low BBB这个朋友。

 

单独以f1为例:

 

def w1(func):    def inner():        print 'gongneng1'        func()        print 'gongneng2'    return inner @w1def f1():    print 'f1' f1()
View Code

当执行的时候,python是由上到下执行的,首先执行到def w1(func):这里把def w1(func)加载到内存

当执行到@w1的时候@w1是python的语法糖!他会把他下面的函数进行封装。

把f1这个函数作为def w1(func)的参数传进去!就是:f1()=w1(f1)

然后def w1(func):  == w1(f1)就会执行:

 

def inner():    print 'gongneng1'    func()   #func()  == f1()“原函数”    print 'gongneng2'return inner  #然后把封装后的函数输出给原函数

@w1就相当于做了一个替换

def f1()  <==> def inner()

@w1def f1():         #  ==def inner() :    print 'f1'    #           print 'gongneng1'                  #           func()                  #           print 'gongneng2'

二、被装饰的函数如果有参数呢?

def w1(func):    def inner(arg):        # 验证1        # 验证2        # 验证3        return func(arg)    return inner @w1def f1(arg):    print 'f1' 一个参数  ################################def w1(func):    def inner(arg1,arg2):        # 验证1        # 验证2        # 验证3        return func(arg1,arg2)    return inner @w1def f1(arg1,arg2):    print 'f1' 两个参数################################def w1(func):    def inner(arg1,arg2,arg3):        # 验证1        # 验证2        # 验证3        return func(arg1,arg2,arg3)    return inner @w1def f1(arg1,arg2,arg3):    print 'f1' 三个参数

用动态参数搞定!

def w1(func):    def inner(*args,**kwargs):        # 验证1        # 验证2        # 验证3        return func(*args,**kwargs)    return inner  @w1def f1(arg1,arg2,arg3):    print 'f1'

三、一个函数可以被多个装饰器装饰吗?

def w1(func):    def inner(*args,**kwargs):        print 'gongneng1'        func(*args,**kwargs)        print 'gongneng2'    return innerdef w2(func):    def inner(*args,**kwargs):        print 'gongneng3'        func(*args,**kwargs)        print 'gongneng4'    return inner @w1@w2def f1(arg,arg2,arg3):    print arg,arg2,arg3 f1('nihao','tianshuai','shuaige')

输出结果:

gongneng1gongneng3nihao tianshuai shuaigegongneng4gongneng2

四、还有什么更吊的装饰器吗?

def
Filter
(a1,a2):
    
def
outer(main_func):
        
def
wrapper(request,kargs):
            
print
a1
            
main_result
=
main_func(request,kargs)
            
print
a2
                
return
main_result
        
return
wrapper
    
return
outer
 
@Filter
(f5, f6)
def
Index(request,kargs):
    
print
'index'
     
'''
1、第一步:把def Filter(a1,a2): 加载到内存
2、第二步:@Filter(f5, f6)  == 调用了装饰器  == @outer 然后返回给函数
3、第散步:执行outer函数并返回给index函数  Index == wrapper
4、执行wrapper 函数,这样做的意义就是除了原函数给的参数外,装饰器也可以调用自己定义的参数

 

转载于:https://www.cnblogs.com/liuyang1987/p/6144662.html

你可能感兴趣的文章
开源SIP服务器加密软件NethidPro升级
查看>>
Apache Pulsar中的地域复制,第1篇:概念和功能
查看>>
南京大学周志华教授当选欧洲科学院外籍院士
查看>>
计算机网络与Internet应用
查看>>
oracle在线迁移同步数据,数据库报错
查看>>
linux性能剖析工具
查看>>
flutter中的异步
查看>>
计算机高手也不能编出俄罗斯方块——计算机达人成长之路(16)
查看>>
# 2017-2018-1 20155224 《信息安全系统设计基础》第七周学习总结
查看>>
scikit-learn预处理实例之一:使用FunctionTransformer选择列
查看>>
Oracle11G 卸载步骤
查看>>
Mars说光场(3)— 光场采集
查看>>
中小企业客户营收增长将成微博2016年主推动力
查看>>
第一个掘金文章
查看>>
我的友情链接
查看>>
微信Windows版无法备份聊天记录
查看>>
Github上传代码菜鸟超详细教程
查看>>
资金项目性能优化
查看>>
Java将图片处理成背景透明的圆形图片
查看>>
知道IP地址怎么查看mac地址
查看>>