前言

前面一篇对python装饰器有了初步的了解了,但是还不够完美,领导看了后又提出了新的需求,希望运行的日志能显示出具体运行的哪个函数。

name__和__doc

__name__用于获取函数的名称,__doc__用于获取函数的docstring内容(函数的注释)

import time

def func_a(a):
'''func_a --> hello'''
print("hello"+a)
time.sleep(0.5)
return True def func_b(b, c="xx"):
'''func_b --> world'''
print("world"+b+c)
time.sleep(0.8)
return True if __name__ == '__main__':
print(func_a.__name__) # 结果 func_a
print(func_a.__doc__) # func_a --> hello
print(func_b.__name__) # func_b
print(func_b.__doc__) # func_b --> world

装饰器加函数名称日志

在装饰器里面添加2行代码,打印正在运行函数的名称和docstring内容

import time

def runtime(func):
'''runtime decorators'''
def wrapper(*args, **kwargs):
'''wrapper inner fuction'''
print("running function : %s" % func.__name__)
print("docstring: %s" % func.__doc__)
start = time.time()
f = func(*args, **kwargs) # 原函数
end = time.time()
print("运行时长:%.4f 秒" % (end-start))
return f
return wrapper @runtime
def func_a(a):
'''func_a --> hello'''
print("hello"+a)
time.sleep(0.5)
return True @runtime
def func_b(b, c="xx"):
'''func_b --> world'''
print("world"+b+c)
time.sleep(0.8)
return True if __name__ == '__main__':
func_a("a")
print(func_a.__name__)
print(func_a.__doc__)

运行结果

running function : func_a
docstring: func_a --> hello
helloa
运行时长:0.5008 秒
wrapper
wrapper inner fuction

从运行的结果可以看出,func_a.__name__运行的结果是wrapper, func_a.__doc__运行的结果是wrapper inner fuction。

也就是说被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),那这个问题如何解决呢?

这就需要用到functools里面的一个wraps函数了

functools

当func_a函数被装饰后,导致了一个副作用:自身的函数属性和docstring内容变成了wrapper函数的属性了。

这里需用到functools里面的一个wraps的装饰器来消除这样的副作用。

import time
from functools import wraps def runtime(func):
'''runtime decorators'''
@wraps(func)
def wrapper(*args, **kwargs):
'''wrapper inner fuction'''
print("running function : %s" % func.__name__)
print("docstring: %s" % func.__doc__)
start = time.time()
f = func(*args, **kwargs) # 原函数
end = time.time()
print("运行时长:%.4f 秒" % (end-start))
return f
return wrapper

只需在wrapper函数上加上@wraps(func)即可解决

运行结果

running function : func_a
docstring: func_a --> hello
helloa
运行时长:0.5004 秒
func_a
func_a --> hello

类装饰器

带参数的装饰器,可以写成类装饰器

import time
from functools import wraps class runtime(object):
'''runtime class decorators'''
def __init__(self, slowly=1):
self.slowly = slowly def __call__(self, func):
@wraps(func)
def wrapper(*args, **kwargs):
'''wrapper inner fuction'''
print("running function : %s" % func.__name__)
print("docstring: %s" % func.__doc__)
start = time.time()
f = func(*args, **kwargs) # 原函数
end = time.time()
t = end-start
time.sleep((self.slowly-1)*t) # 延迟效果
new_end = time.time()
print("运行时长:%.4f 秒" % (new_end-start))
return f
return wrapper @runtime(1.5)
def func_a(a):
'''func_a --> hello'''
print("hello"+a)
time.sleep(0.5)
return True @runtime()
def func_b(b, c="xx"):
'''func_b --> world'''
print("world"+b+c)
time.sleep(0.8)
return True if __name__ == '__main__':
func_a("a")
print(func_a.__name__)
print(func_a.__doc__)

运行结果

running function : func_a
docstring: func_a --> hello
helloa
运行时长:0.7522 秒
func_a
func_a --> hello

python自动化交流 QQ群:779429633

python笔记36-装饰器之wraps的更多相关文章

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

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

  2. Python笔记:装饰器

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

  3. 20.python笔记之装饰器

    装饰器 装饰器是函数,只不过该函数可以具有特殊的含义,装饰器用来装饰函数或类,使用装饰器可以在函数执行前和执行后添加相应操作. 装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插 ...

  4. Python装饰器之functools.wraps的作用

    # -*- coding: utf-8 -*- # author:baoshan def wrapper(func): def inner_function(): pass return inner_ ...

  5. guxh的python笔记三:装饰器

    1,函数作用域 这种情况可以顺利执行: total = 0 def run(): print(total) 这种情况会报错: total = 0 def run(): print(total) tot ...

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

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

  7. Python 中实现装饰器时使用 @functools.wraps 的理由

    Python 中使用装饰器对在运行期对函数进行一些外部功能的扩展.但是在使用过程中,由于装饰器的加入导致解释器认为函数本身发生了改变,在某些情况下——比如测试时——会导致一些问题.Python 通过  ...

  8. Python学习笔记:装饰器

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

  9. Python函数的装饰器修复技术(@wraps)

    @wraps 函数的装饰器修复技术,可使被装饰的函数在增加了新功能的前提下,不改变原函数名称,还继续使用原函数的注释内容: 方便了上下文环境中不去更改原来使用的函数地方的函数名: 使用方法: from ...

随机推荐

  1. maven工程仿springboot手写代码区分开发测试生产

    读取代码: package com.jz.compute.mc.v2.config; import java.util.Enumeration; import java.util.ResourceBu ...

  2. mvn-dependencies-vs-dependencyManagement

    dependencyManagement里只是声明依赖,并不实现引入,因此子项目需要显式的声明需要用的依赖. dependencies 相对于dependencyManagement,所有声明在dep ...

  3. spark 更改日志输出级别

    package com.ideal.test import org.apache.spark.{SparkConf, SparkContext} import org.apache.log4j.{Le ...

  4. OTP详解

    OTP(One Time Programmable)是单片机的一种存储器类型,意思是一次性可编程:程序烧入单片机后,将不可再次更改和清除. 随着嵌入式应用的越来越广泛,产品的安全也显得越来越重要.一方 ...

  5. 解决 Url is blocked: Requests to the local network are not allowed

    问题:         我在学习GitLab + Jenkins 自动化部署时,在GitLab的 MyProject => Settings => Integrations中输入完 &qu ...

  6. linux查看当前路径命令 pwd

    pwd命令能够显示当前所处的路径. 这个命令比较简单,如果有时在操作过程中忘记了当前的路径,则可以通过此命令来查看路径,其执行方式为: # pwd /home/your_username 第一行为运行 ...

  7. LOJ#2409. 「THUPC 2017」小 L 的计算题 / Sum(生成函数)

    题意 给定一个长为 \(n\) 的序列 \(\{a_i\}\) 对于 \(k \in [1, n]\) 求 \[ f_k = \sum_{i = 1}^{n} a_i^k \pmod {9982443 ...

  8. 【Maven基础入门】01 Maven的安装与环境变量的配置

    写在前面: Mavne,作为一个优秀的项目构建工具,虽说我们平时在使用的时候或多或少的会使用到它,但了解仅限于它能构建项目,然后其他的就不知道了. 以及仓库.POM父类文件.等等. 工欲善其事,必先利 ...

  9. WPF 的 VisualBrush 只刷新显示的视觉效果,不刷新布局范围

    原文:WPF 的 VisualBrush 只刷新显示的视觉效果,不刷新布局范围 WPF 的 VisualBrush 可以帮助我们在一个控件中显示另一个控件的外观.这是非常妙的功能. 但是本文需要说其中 ...

  10. C# 录音和变调

    一直想研究下录音 正好有个项目有机会使用一下强大的 NAudio (https://github.com/naudio/NAudio)库 录音 NAudio 录音类库 public class NAu ...