我的编程空间,编程开发者的网络收藏夹
学习永远不晚

python wraps那点儿事儿

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

python wraps那点儿事儿

 一个需求的实现

当前,我们有这么一个小的需求:通过装饰器来计算函数执行的时间

计算出这个函数的执行时长

def add(x,y):   # add = TimeIt(add)
    time.sleep(1)
    'this is add'
    return x + y



装饰器实现

import time
import datetime
from functools import wraps
class TimeIt:
    def __init__(self,fn):
        print('init')
        self._fn = fn
    def __call__(self, *args, **kwargs):
        start = datetime.datetime.now()
        ret = self._fn(*args, **kwargs)
        delta = datetime.datetime.now() - start
        print(delta)
        return ret
@TimeIt
def add(x,y):   # add = TimeIt(add)
    time.sleep(1)
    'this is add'
    return x + y
add(1,2)
print(add.__doc__)
print(add.__name__)


我们所看到的信息如下:

Traceback (most recent call last):
  File "H:/Python_Project/test2/3.py", line 33, in <module>
    print(add.__name__)
AttributeError: 'TimeIt' object has no attribute '__name__'


那么问题来了,在打印__doc__  和 __name__ 的时候看到返回的并非是我们想要的,因为已经被包装到TimeIt中的可调用对象,所以,现在它是一个实例了,实例是不能调用__name__的;所以,我们来手动模拟一下,将其伪装写入__doc__ 和 __name__



改造

手动拷贝:粗糙的改造方式,将其__doc__ __name__强行复制到实例中

self无非是我们当前所绑定的类实例,fn是通过装饰器传递进来的add,我们将fn的doc 和 name 作为源强行的赋值到self中,如下:

class TimeIt:
    def __init__(self,fn):
        print('init')
        self._fn = fn
# 函数的doc 拷贝到 fn中
        self.__doc__ = self._fn.__doc__ 
        self.__name__ = self._fn.__name__

这样效果肯定是不好的,这样做就是为了得知其保存位置,那么接下来引入wraps模块


引入wraps

wraps本质是一个函数装饰器,通过接收一个参数再接收一个参数进行传递并处理,反正网上也一堆使用方法,举例不再说明,但是这里需要将函数调用的等价式摸清

使用方式:

from functools import wraps
def looger(fn):
    @wraps(fn)       
    def wrapper(*args, **kwargs):
        xxxxxxxx

  等价式关系 : @wraps(fn) = ( a = wraps(fn);  a(wrapper) )

 可以看出,源是传递进来的fn,目标是self,也就是wrapper


过程分析

首先我们通过编辑器跟进到函数内部


def wraps(wrapped,
       assigned = WRAPPER_ASSIGNMENTS,
       updated = WRAPPER_UPDATES):
    """Decorator factory to apply update_wrapper() to a wrapper function
       Returns a decorator that invokes update_wrapper() with the decorated
       function as the wrapper argument and the arguments to wraps() as the
       remaining arguments. Default arguments are as for update_wrapper().
       This is a convenience function to simplify applying partial() to
       update_wrapper().
    """

可看到wraps中,需要传递几个参数,跟进到assigned,被包装的函数才是class="lazy" data-src源,也就是说被外部的更新掉

查看 assigned = WRAPPER_ASSIGNMENTS

通过WRAPPER_ASSIGNMENTS 发现是被跳转到了

WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
                       '__annotations__')
WRAPPER_UPDATES = ('__dict__',)
def update_wrapper(wrapper,
                   wrapped,
                   assigned = WRAPPER_ASSIGNMENTS,
                   updated = WRAPPER_UPDATES):

可看到wraps中,需要传递几个参数,跟进到assigned,被包装的函数才是class="lazy" data-src源,也就是说被外部的更新掉
查看 assigned = WRAPPER_ASSIGNMENTS

那么赋值更新哪些东西呢?就是这些属性,如下所示
WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
                      '__annotations__')

而updated = WRAPPER_UPDATES  所覆盖的则就是从WRAPPER_UPDATES = ('__dict__',)的基础上在执行了更新操作WRAPPER_ASSIGNMENTS,说白了全是在当前__dict__中进行
如果存在字典之类的属性要做的是并不是覆盖字典,而是在他们的字典中将自身的信息覆盖或增加等更新操作
assigned  只有默认值,但是够我们用了

对象属性的访问
继续往下查看代码:
for attr in assigned:
   try:
       value = getattr(wrapped, attr)
   except AttributeError:
       pass
   else:
       setattr(wrapper, attr, value)
for attr in updated:
   getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
# Issue #17482: set __wrapped__ last so we don't inadvertently copy it
# from the wrapped function when updating __dict__
wrapper.__wrapped__ = wrapped
# Return the wrapper so this can be used as a decorator via partial()
return wrapper

它是通过反射机制通过找到__dict__,如果存在则返回,没有则触发setattr将value写入到__dict__ 
value = getattr(wrapped, attr)      从attr反射获取了属性,attr就是assigent,而assigent就是WRAPPER_ASSIGNMENTS 定义的属性
setattr(wrapper, attr, value)       如果没有找到则动态的加入到其字典中
wrapper.__wrapped__ = wrapped       将wrapper拿到之后为其加入了一个属性,也属于一个功能增强,把wrapperd 也就是被包装函数,将add的引用交给了def wrapper(*args, **kwargs) ; 凡是被包装过的都会增加这个属性

说白了 wraps就是调用了update_wrapper,只不过少了一层传递

那么再回到wraps中(这下面为啥刷不出来格式?)
def wraps(wrapped,
         assigned = WRAPPER_ASSIGNMENTS,
         updated = WRAPPER_UPDATES):

         
是不是感觉少了些东西?实际它是调用了partial偏函数
return partial(update_wrapper, wrapped=wrapped,
              assigned=assigned, updated=updated)

通过偏函数,update_wrapper 对应的wrapper ,送入一个函数,其他 照单全收
接下来又会引入一个新的函数,partial具体分析后期再写
总之一句话:wraps 是通过装饰器方式进行传参并增强,将需要一些基础属性以反射的方式从源中赋值到当前dict中,并使用偏函数生成了一个新的函数并返回


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

python wraps那点儿事儿

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

python wraps那点儿事儿

一个需求的实现当前,我们有这么一个小的需求:通过装饰器来计算函数执行的时间计算出这个函数的执行时长def add(x,y):   # add = TimeIt(add)    time.sleep(1)    'this is add'  
2023-01-31

详解Android中fragment和viewpager的那点事儿

在之前的博文《Android 中使用 ViewPager实现屏幕页面切换和页面轮播效果》和《详解Android中Fragment的两种创建方式》以及《Android中fragment与activity之间的交互(两种实现方式)》中我们介绍了
2022-06-06

关于 sudo 的那些事儿

觉得你已经了解了 sudo 的所有知识了吗?再想想。大家都知道 sudo,对吗?默认情况下,该工具已安装在大多数 Linux 系统上,并且可用于大多数 BSD 和商业 Unix 变体。不过,在与数百名 sudo 用户交谈之后,我得到的最常见
2023-06-05

浅谈Python基础之列表那些事儿

一、列表的格式二、列表的相关操作("增"、"删"、"改",“查”) <1> 添加元素 append()通过append可以向列表添加元素。 例:运行结果:<2> 修改元素("改") 修改元素的时候,要通过下标来确定要修改的是哪个元素,然后才
2022-06-02

C# 解析Excel中的那些事儿

在C#中解析Excel文件是一个常见的任务,可以使用一些类库来实现。1. 使用Microsoft Office Interop Excel:这是官方提供的一种解析Excel文件的方法。首先需要安装Microsoft Office并引用Mic
2023-09-09

Java和Docker限制的那些事儿

作者:kelvinjin2009 来源:程序师原文链接:http://www.techug.com/post/java-and-docker-memory-limits.html Java和Docker不是天然的朋友。 Docker可以设置
2023-06-04

web前端:前端架构那些事儿

编程学习网:前端即网站前台部分,运行在PC端,移动端等浏览器上展现给用户浏览的网页。随着互联网技术的发展,HTML5,CSS3,前端框架的应用,跨平台响应式网页设计能够适应各种屏幕分辨率,完美的动效设计,给用户带来极高的用户体验。
web前端:前端架构那些事儿
2024-04-23

内存吞金兽(Elasticsearch)的那些事儿 -

系列目录内存吞金兽(Elasticsearch)的那些事儿 -- 认识一下内存吞金兽(Elasticsearch)的那些事儿 -- 数据结构及巧妙算法内存吞金兽(Elasticsearch)的那些事儿 -- 架构&三高保证内存吞金兽(Elasticsearch
内存吞金兽(Elasticsearch)的那些事儿 -
2018-08-15

Python与Cisco 的事儿

前几天写了一段代码,是用来检查思科设备的端口运行状态的,只是中间有些bug或是存在安全问题,比如密码写在脚本里,对网络不可以达的设备没有进行判断并加以跳过。以下对前两天写的代码进行修改。#!/usr/bin/python from netm
2023-01-31

科技那些事儿阿里云代理商

自2004年阿里巴巴在杭州创立以来,如今的阿里巴巴已成为中国科技领域的一张名片。阿里巴巴在云计算、人工智能、大数据、物联网等领域取得了令人瞩目的成就。今天,科技那些事儿就要带您一起探讨阿里云这个神秘而强大的科技公司。阿里云阿里云,又名阿里云智能,是阿里巴巴旗下的云计算服务平台,也是阿里巴巴在云计算领域的代表性产品。它致
科技那些事儿阿里云代理商
2023-10-28

关于索引我能说的那些事儿

本文是自己对MySQL的InnoDB索引的理解,如有错误,还望不吝指出。1 索引  索引两个大字往那里一摆,刚接触不久的朋友可能对这个概念有点陌生,不好理解。没有关系,先用一个简单的例子入手,比方说现在我们要从一本字典中查一个牛字,那么我们可以从目录中的n字母
关于索引我能说的那些事儿
2015-01-11

软考那些事儿看这一篇就够了!

  近几年来,各行各业的职业资质考试持续发热,其中,软考的报名人数更是一马当先逐年暴增。说起软考证书,大概还有很多朋友都不大认识,甚至还有这样的疑问:为什么这么多人考软考?软考是什么?今天小希就为大家详细介绍下“软考”,一起来看看吧~  软考的前世今生  计算机软件资格考试(即“软考
软考那些事儿看这一篇就够了!
2024-04-19

关于iOS自适应cell行高的那些事儿

前言其实早就准备写这篇文章了,但是一直没有系统去整理一下相关的demo,加上最近离职了,各种事情忙的有点郁闷,所以一直拖沓了下来。回家休息了一段时间想起来写了一半的demo,在还没找工作的这段空挡时间抽空完善了一下再写篇说明文档备忘一下。
2022-05-31

Python与Cisco的事儿之三

以下代码可以实现登录网络设备后通过show cdp nei 命令查看邻居设备,然后利用拼接的方式来增加描述,最后再写进相对应的网络设备的接口。#!/usr/bin/pythonfrom netmiko import ConnectHandl
2023-01-31

Python与Cisco 的事儿之二

坚持连续Python大战CiscoNetwork。 #!/usr/bin/python from netmiko import ConnectHandlerfrom netmiko.ssh_exception import NetMikoT
2023-01-31

Python与Cisco的事儿之四

以下代码实现的流程: cdp -->获取相应链接的信息-->自动写进设备相对应的端口--->configure保存-->configure备份到TFTP服务器!#!/usr/bin/pythonfrom netmiko import Con
2023-01-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录