zoukankan      html  css  js  c++  java
  • 【Python学习之二】装饰器

    装饰器

      首先,给出装饰器的框架:

    def log(func):
        def wrapper(*args, **kw):
            print('call %s():' % func.__name__)
            return func(*args, **kw)
        return wrapper
    
    @log
    def now():
        print('2018-6-14')

      Python装饰器,本质上就是一个高阶函数。作用是给其它函数增加新的功能。借用python的@语法,可以将一个高阶函数定义为装饰器。

    @符号的作用

      但是,在学习廖雪峰老师的Python教程时,似懂非懂,尤其是看到@这个符号的时候,感觉一头雾水。现在回想来看,只要百度一下就能知道@符号在Python中的作用。它的作用就是修饰一个函数。位置在被修饰的函数的前一行,@之后是修饰函数的函数。 例如上述的 @log 起到的作用就是相当于执行了语句: now = log(now) ,现在或许难以理解这行代码的作用。接下来,进行一个对比,就能知道装饰器的威力了。

    使用装饰器之前

    #给下列函数增加新功能:调用函数时,打印函数名。
    #要求:(1)不改变函数的定义,不改变函数的调用方式。
    def now():
        print('2015-3-25')
    
    #增加一个高级函数 def call_name(func): def wrapper(
    *args, **kw): print('call %s()' % func.__name__) return func(*args, **kw) return wrapper
    #调用now函数 now
    = call_name(now) #调用方式还是改变了(增加了一行) now()

    使用装饰器之后

    #给下列函数增加新功能:调用函数时,打印函数名。
    #要求:(1)不改变函数的定义,不改变函数的调用方式。
    
    #写一个装饰器
    def call_name(func):
        def wrapper(*args, **kw):
            print('call %s()' % func.__name__)
            return func(*args, **kw)
        return wrapper
    
    
    @call_name               #相当于执行语句 call_name(now)
    def now():
        print('2015-3-25')
    
    
    #调用now函数
    now()                     #这才是真正没改变调用方式

      通过对比,我对装饰器的作用了解更加深刻了。下面是带参数的装饰器:

    带参数的装饰器

      上例,如果装饰器call_name(func)本身还要带参数,那么需要更加复杂的高阶函数。

     1 def call_name(text):                   #text为装饰器的参数
     2     def decorator(func):
     3         def wrapper(*args, **kw):
     4             print('%s call %s()' % (text, func.__name__))
     5             return func(*args, **kw)
     6         return wrapper
     7     return decorator
     8 
     9 
    10 @call_name('execute ')                #相当于 now = log('execute')(now)
    11 def now():
    12     print('2015-3-25')
    13 
    14 
    15 # 调用now函数
    16 now()

    装饰器练习

      设计一个decorator(装饰器),它可作用于任何函数上,并打印该函数的执行时间:

     1 import time
     2 
     3 import functools
     4 
     5 
     6 def metric(fn):
     7     @functools.wraps(fn)
     8     def wrapper(*args, **kw):
     9         print('%s executed in %s' %
    10               (fn.__name__, time.asctime(time.localtime(time.time()))))
    11         return fn(*args, **kw)
    12     return wrapper
    13 
    14 # 测试
    15 
    16 
    17 @metric
    18 def fast(x, y):
    19     time.sleep(0.0012)
    20     return x + y
    21 
    22 
    23 @metric
    24 def slow(x, y, z):
    25     time.sleep(0.1234)
    26     return x * y * z
    27 
    28 
    29 f = fast(11, 22)
    30 s = slow(11, 22, 33)
    31 
    32 print(f)
    33 print(s)
    34 
    35 if f != 33:
    36     print('测试失败!')
    37 elif s != 7986:
    38     print('测试失败!')
    39 else:
    40     print('测试成功!')

      编写一个decorator,能在函数调用的前后打印出'begin call'和'end call'的日志:

     1 def call_name(func):
     2     def wrapper(*args, **kw):
     3         print('begin call:')
     4         print('call %s()' % func.__name__)
     5         call = func(*args, **kw)               #函数在此时调用
     6         print('end call.')
     7         return call
     8     return wrapper
     9 
    10 
    11 @call_name
    12 def now():
    13     print('2015-3-25')
    14 
    15 
    16 # 调用now函数
    17 now()

      加大难度,写出一个@call_name的decorator,使它既支持:

    @log
    def f():
        pass

      又支持:

    @log('execute')
    def f():
        pass

      源码实现:

     1 import functools
     2 
     3 
     4 def call_name(text):
     5     if isinstance(text, str):      #通过参数能够判断两种模式
     6         def decorator(func):
     7             @functools.wraps(func)
     8             def wrapper(*args, **kw):
     9                 print('%s call %s()' % (text, func.__name__))
    10                 return func(*args, **kw)
    11             return wrapper
    12         return decorator
    13     else:
    14         @functools.wraps(text)
    15         def wrapper(*args, **kw):
    16             print('call %s()' % text.__name__)
    17             return text(*args, **kw)
    18         return wrapper
    19 
    20 
    21 @call_name
    22 def now():
    23     print('2015-3-25')
    24 
    25 
    26 # 调用now函数
    27 now()
    
    
    
  • 相关阅读:
    获取文件当前目录及其大小
    PLC工作原理动图,一图搞懂一个原理
    欧拉角的详解
    欧拉角的详解
    PLC/Pragmas
    ASCII码对照表
    C++ 的关键字(保留字)完整介绍
    C++ 基本语法
    pytorch笔记1
    pytorchnum_flat_features(x)
  • 原文地址:https://www.cnblogs.com/cjvae/p/9182522.html
Copyright © 2011-2022 走看看