ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Python 之 装饰器及文档字符串 随性笔记

2021-02-11 22:04:04  阅读:213  来源: 互联网

标签:__ .__ Python wrapper datetime 器及 随性 add fn


Python 之 装饰器及文档字符串 随性笔记

1、装饰器

  • 装饰器(Decorators)是 Python 的一个重要部分。简单地说:它们是修改其他函数的功能的函数。他们有助于让我们的代码更简短,也更Pythonic(Python范儿)
  • 装饰器分为 无参装饰器 和 有参装饰器
  • 装饰器是一个函数,函数作为它的形参
  • 无参装饰器实际上就是单形参函数
  • 有参装饰器实际上就是多形参函数
  • 可以使用 @functionname@functionname(参数列表) 方式,简化调用
  • 装饰器可以是高阶函数,但装饰器是对传入函数的功能的装是(功能增强)

2、文档字符串

  • Python 文档字符串 Documentation Strings
  • 在函数语句块的第一行,且习惯是多行的文本,所以多使用三引号
  • 惯例是首字母大写,第一行写概述,空一行,第三行写详细描述
  • 可以使用特殊属性__doc__访问这个文档
def add(x, y):
    """
    This is a function of addition.
    """
    return x + y

print("name = {}\ndoc = {}".format(add.__name__, add.__doc__, add.__defaults__))
print('=' * 55)
print(help(add))

name = add
doc = 
    This is a function of addition.
    
=======================================================
Help on function add in module __main__:

add(x, y)
    This is a function of addition.

None

3、装饰器执行过程

3.1 请浏览以下代码

  • 装饰器 代码

    import datetime, functools
    
    def logger(fn):
        print('=== logger start ===')
        print('{} fn_id is {}'.format(fn.__name__, id(fn)))
        @functools.wraps(fn)
        def wrapper(*args, **kwargs):
            print('=== wrapper start ===')
            print('{} fn_id is {}'.format(fn.__name__, id(fn)))
            start = datetime.datetime.now()
            ret = fn(*args, **kwargs)
            delta = (datetime.datetime.now() - start).total_seconds()
            if delta > 3:
                print('Too slow.')
            print('=== wrapper end ===')
            return ret
        print('=== logger end ===')
        return wrapper
    
  • 其它函数代码,注意在 被装饰函数 没有被调用的时候,即在被装饰 函数定义的时候,装饰器已经执行过了,注意print语句

    # add1(args) => logger(add1)(args) => functools.wraps(add1)(wrapper)(args)
    @logger 
    def add1(x, y):
        time.sleep(2)
        return x + y
    
    print('=' * 25)
    
    @logger  # add2 => logger(add2)
    def add2(x, y, z):
        time.sleep(4)
        return x + y + z
    
    print('=' * 25)
    
    print(add1.__name__, add2.__name__)
    
    # 上述代码执行结果
    === logger start ===
    add1 fn_id is 121600328
    === logger end ===
    =========================
    === logger start ===
    add2 fn_id is 121601048
    === logger end ===
    =========================
    add1 add2
    
  • 执行 被装饰函数

print('add1 >>>', add1(1, 2))
print('add2 >>>', add2(1, 2, 3))
# 上述代码执行结果
=== wrapper start ===
add1 fn_id is 121600328
=== wrapper end ===
add1 3
=== wrapper start ===
add2 fn_id is 121601048
Too slow.
=== wrapper end ===
add2 6

3.2 结合以下问题进行思考

  • logger 什么时候执行

    定义 被装饰函数 的时候执行
    
  • logger 执行过几次

    装饰几个函数,执行几次
    
  • wraps 装饰器什么时候执行

    执行 被装饰函数 的时候
    
  • wraps 装饰器执行过几次

    每执行一个 被装饰函数,执行一次
    
  • wrapper__name__ 等属性被覆盖过几次

    没有覆盖,每次调用都不是同一个函数对象
    

4、装饰器函数的版本迭代改进

4.1 第一版,函数属性会被替换

import datetime
import time

def logger(fn):
    def wrapper(*args, **kwargs):
        """I am wrapper."""
        start = datetime.datetime.now()
        ret = fn(*args, **kwargs)
        duration = datetime.datetime.now() - start
        print('function {} took {}s.'.format(fn.__name__, duration.total_seconds()))
        return ret
    return wrapper

@logger   # 相当于 add = logger(add)
def add(x,y):
    """I am add."""
    time.sleep(2)
    return x + y

print(add(5, y = 8))
print(add.__name__, add.__doc__)
function add took 2.0s.
13
wrapper I am wrapper.

4.2 第二版,构造函数还原函数属性

import datetime
import time

def copy_properties(src, dst):
    dst.__name__ = src.__name__
    dst.__doc__ = src.__doc__

def logger(fn):
    def wrapper(*args, **kwargs):
        """I am wrapper."""
        start = datetime.datetime.now()
        ret = fn(*args, **kwargs)
        duration = datetime.datetime.now() - start
        print('function {} took {}s.'.format(fn.__name__, duration.total_seconds()))
        copy_properties(fn, wrapper)
        return ret
    return wrapper

@logger   # 相当于 add = logger(add)
def add(x,y):
    """I am add."""
    time.sleep(2)
    return x + y
              
print(add(5, y = 8))
print(add.__name__, '|||', add.__doc__)
function add took 2.0s.
13
add ||| I am add.

4.3 第三版,柯里化新建函数

import datetime
import time

# 柯里化
def copy_properties(src):
    def _copy_properties(dst):
        dst.__name__ = src.__name__
        dst.__doc__ = src.__doc__
        return dst
    return _copy_properties

def logger(fn):
    def wrapper(*args, **kwargs):
        """I am wrapper."""
        start = datetime.datetime.now()
        ret = fn(*args, **kwargs)
        duration = datetime.datetime.now() - start
        print('function {} took {}s.'.format(fn.__name__, duration.total_seconds()))
        # copy_properties(fn)(wrapper) => _copy_properties(wrapper)
        copy_properties(fn)(wrapper)
        return ret
    return wrapper

@logger   # 相当于 add = logger(add)
def add(x,y):
    """I am add."""
    time.sleep(2)
    return x + y
              
print(add(5, y = 8))
print(add.__name__, '|||', add.__doc__)
function add took 2.0s.
13
add ||| I am add.

4.4 第四版,改造成装饰器

import datetime
import time

def copy_properties(src):
    def _copy_properties(dst):
        dst.__name__ = src.__name__
        dst.__doc__ = src.__doc__
        return dst
    return _copy_properties

def logger(fn):
    @copy_properties(fn) 
    # 带参装饰器
    # wrapper => copy_properties(fn)(wrapper) => _copy_properties(wrapper)
    def wrapper(*args, **kwargs):
        """I am wrapper."""
        start = datetime.datetime.now()
        ret = fn(*args, **kwargs)
        duration = datetime.datetime.now() - start
        print('function {} took {}s.'.format(fn.__name__, duration.total_seconds()))
        # copy_properties(fn)( wrapper)
        return ret
    return wrapper

@logger   
# 相当于 add = logger(add) => add = wrapper
# 无参装饰器,本质上等效为 单参数 的函数
def add(x,y):  # lambda x, y:x + y
    """I am add."""
    print('===== call add =====')
    time.sleep(2)
    return x + y
              
print(add(5, y = 8))
print(add.__name__, '|||', add.__doc__)
===== call add =====
function add took 2.0s.
13
add ||| I am add.

4.5 第五版,使用 functools

from functools import update_wrapper, wraps
import datetime
import time

def logger(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        """I am wrapper."""
        start = datetime.datetime.now()
        ret = fn(*args, **kwargs)
        duration = datetime.datetime.now() - start
        print('function {} took {}s.'.format(fn.__name__, duration.total_seconds()))
        return ret
    return wrapper

@logger   
def add(x,y):
    """I am add."""
    time.sleep(2)
    return x + y
              
print(add(5, y = 8))
print(add.__name__, '|||', add.__doc__)
function add took 2.0s.
13
add ||| I am add.

4.6 第六版,增加函数执行时间判断

from functools import update_wrapper, wraps
import datetime
import time


def logger(duration=5):
    def _logger(fn):
        @wraps(fn)  
        def wrapper(*args, **kwargs):
            """I am wrapper."""
            start = datetime.datetime.now()
            ret = fn(*args, **kwargs)
            delta = (datetime.datetime.now() - start).total_seconds()
            if delta > duration:
                print('function {} took {:.2f}s.'.format(fn.__name__, delta))
            else:
                print('function {} run so fast.'.format(fn.__name__))
            return ret
        return wrapper
    return _logger

@logger(3) 
def add(x,y):
    """I am add."""
    time.sleep(2)
    return x + y
              
print(add(5, y = 8))
print(add.__name__, '|||', add.__doc__)
function add run so fast.
13
add ||| I am add.

4.7 第七版,把之前函数进行抽象

from functools import update_wrapper, wraps
import datetime
import time

def x(delta, func, duration):
    if delta > duration:
        print('function {} took {:.2f}s. It run too slow.'.format(func.__name__, delta))
    
def logger(duration=2, func=x):
    def _logger(fn):
        @wraps(fn)  # wrapper = update_wrapper(fn)(wrapper)
        def wrapper(*args, **kwargs):
            start = datetime.datetime.now()
            ret = fn(*args, **kwargs)
            delta = (datetime.datetime.now() - start).total_seconds()
            func(delta, fn, duration)
            return ret
        return wrapper
    return _logger

@logger()   
def add(x,y):  
    time.sleep(3)
    return x + y
              
print(add(5, y = 8))
print(add.__name__, '|||', add.__doc__)
function add took 3.00s. It run too slow.
13
add ||| None

标签:__,.__,Python,wrapper,datetime,器及,随性,add,fn
来源: https://blog.csdn.net/weixin_44983653/article/details/113789789

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有