iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >python wraps那点儿事儿
  • 293
分享到

python wraps那点儿事儿

事儿pythonwraps 2023-01-31 07:01:23 293人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

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

 一个需求的实现

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

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

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,被包装的函数才是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,被包装的函数才是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中,并使用偏函数生成了一个新的函数并返回


--结束END--

本文标题: python wraps那点儿事儿

本文链接: https://www.lsjlt.com/news/191327.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

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

下载Word文档
猜你喜欢
  • python wraps那点儿事儿
     一个需求的实现当前,我们有这么一个小的需求:通过装饰器来计算函数执行的时间计算出这个函数的执行时长def add(x,y):   # add = TimeIt(add)     time.sleep(1)     'this is add...
    99+
    2023-01-31
    事儿 python wraps
  • 事务Transaction 那点事儿
    Transaction 也就是所谓的事务了,通俗理解就是一件事情。从小,父母就教育我们,做事情要有始有终,不能半途而废。 事务也是这样,不能做一般就不做了,要么做完,要么就不做。也就是说,事务...
    99+
    2022-10-18
  • 详解Android中fragment和viewpager的那点事儿
    在之前的博文《Android 中使用 ViewPager实现屏幕页面切换和页面轮播效果》和《详解Android中Fragment的两种创建方式》以及《Android中fragm...
    99+
    2022-06-06
    viewpager fragment Android
  • 关于 sudo 的那些事儿
    觉得你已经了解了 sudo 的所有知识了吗?再想想。大家都知道 sudo,对吗?默认情况下,该工具已安装在大多数 Linux 系统上,并且可用于大多数 BSD 和商业 Unix 变体。不过,在与数百名 ...
    99+
    2023-06-05
  • 浅谈Python基础之列表那些事儿
    一、列表的格式 二、列表的相关操作("增"、"删"、"改",“查”) <1> 添加元素 append()通过append可以向列表添加元素。 例: 运行结果: <2> 修改元素("改")...
    99+
    2022-06-02
    Python列表操作 python list列表
  • C# 解析Excel中的那些事儿
    在C#中解析Excel文件是一个常见的任务,可以使用一些类库来实现。1. 使用Microsoft Office Interop Ex...
    99+
    2023-09-09
    C#
  • Java和Docker限制的那些事儿
    作者:kelvinjin2009 来源:程序师原文链接:http://www.techug.com/post/java-and-docker-memory-limits.html Java和Docker不是天然的朋友。 Docker可以设置...
    99+
    2023-06-04
  • 小程序内嵌H5那些事儿
    什么是小程序内嵌H5 小程序内嵌H5是指将一个H5页面嵌入到小程序中的一种方式 小程序内嵌H5可以让用户在小程序中直接浏览和使用H5网页 同时也可以让开发者在小程序中使用H5网页的某些功能。 当原有的H5转相似业务逻辑的小程序时 除了内嵌H...
    99+
    2023-08-31
    小程序 前端 微信小程序
  • 内存吞金兽(Elasticsearch)的那些事儿 -
    系列目录 内存吞金兽(Elasticsearch)的那些事儿 -- 认识一下 内存吞金兽(Elasticsearch)的那些事儿 -- 数据结构及巧妙算法 内存吞金兽(Elasticsearch)的那些事儿 -- 架构&三高保证 内存吞金...
    99+
    2018-08-15
    内存吞金兽(Elasticsearch)的那些事儿 -
  • 关于索引我能说的那些事儿
    本文是自己对MySQL的InnoDB索引的理解,如有错误,还望不吝指出。 1 索引   索引两个大字往那里一摆,刚接触不久的朋友可能对这个概念有点陌生,不好理解。没有关系,先用一个简单的例子入手,比方说现在我们要从一本字典中查...
    99+
    2015-01-11
    关于索引我能说的那些事儿
  • 科技那些事儿阿里云代理商
    自2004年阿里巴巴在杭州创立以来,如今的阿里巴巴已成为中国科技领域的一张名片。阿里巴巴在云计算、人工智能、大数据、物联网等领域取得了令人瞩目的成就。今天,科技那些事儿就要带您一起探讨阿里云这个神秘而强大的科技公司。 阿里云 阿里云,又名...
    99+
    2023-10-28
    阿里 事儿 代理商
  • Python与Cisco 的事儿
       前几天写了一段代码,是用来检查思科设备的端口运行状态的,只是中间有些bug或是存在安全问题,比如密码写在脚本里,对网络不可以达的设备没有进行判断并加以跳过。以下对前两天写的代码进行修改。#!/usr/bin/python  from...
    99+
    2023-01-31
    事儿 Python Cisco
  • Java那点儿事之Map集合不为人知的秘密有哪些
    目录前言一、Map二、HashMap的基本概念三、HashMap集合的基本方法与使用四、HashMap集合的遍历五、HashMap集合的综合案例六、总结前言 上期我们说到了Colle...
    99+
    2022-11-12
  • 关于iOS自适应cell行高的那些事儿
    前言 其实早就准备写这篇文章了,但是一直没有系统去整理一下相关的demo,加上最近离职了,各种事情忙的有点郁闷,所以一直拖沓了下来。回家休息了一段时间想起来写了一半的demo,在还...
    99+
    2022-05-31
    cell 自适应 行高
  • Python与Cisco的事儿之三
       以下代码可以实现登录网络设备后通过show cdp nei 命令查看邻居设备,然后利用拼接的方式来增加描述,最后再写进相对应的网络设备的接口。#!/usr/bin/python from netmiko import Connect...
    99+
    2023-01-31
    之三 事儿 Python
  • Python与Cisco 的事儿之二
    坚持连续Python大战CiscoNetwork。 #!/usr/bin/python  from netmiko import ConnectHandler from netmiko.ssh_exception import NetMi...
    99+
    2023-01-31
    之二 事儿 Python
  • Python与Cisco的事儿之四
       以下代码实现的流程: cdp -->获取相应链接的信息-->自动写进设备相对应的端口--->configure保存-->configure备份到TFTP服务器!#!/usr/bin/python from n...
    99+
    2023-01-31
    之四 事儿 Python
  • Java基础详解之面向对象的那些事儿
    目录一、面向对象的理解二、三大特性2.1 继承(extends):2.2 封装(private):2.3 多态:三、自动装箱与自动拆箱3.1 自动装箱3.2 自动拆箱四、小结一、面向...
    99+
    2022-11-12
  • 详细聊聊关于Mysql联合查询的那些事儿
    目录联合查询之union 1. 查询中国各省的ID以及省份名称 2. 湖南省所有地级市ID、名字 3. 用union将他们合并 联合查询之union a...
    99+
    2022-11-12
  • 2020将至,谈谈中小企业创业的那些事儿
    2019正迎来尾声,在创业这场轰轰烈烈的旅途中,有的人名利双收,有的人饱受非议。一入创业深似海,在创业赛道上,很多公司完成了从0到1,却死在从1到100的路上。而小程序的出现,让移动互联网创业走向低门槛。正...
    99+
    2022-10-18
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作