python笔记 __wrapped__

126 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第19天,点击查看活动详情

0 环境

  • 编辑器:pycharm或者vscode
  • 系统版本:windows10
  • python版本:3.9.6

1 wrapped

上下文关键到底是应用在哪块儿的呢。比如现在临时有个小需求,我要给导入、导出加个成功提示,提示内容需要包括导入、导出了多少条,比如说导入,是为了核对是否全部导入了,本来这件事就结束了,后来呢,在这个条数显示的基础上,再追加个耗时的提示。假如很多处要用到它,是不是会想到用装饰器搞定了。例如函数()()这种形式。好比计时,可不可以用上下文管理呢,如下代码:

from datetime import datetime

class Keeptime:
    def __enter__(self):
        self.start = datetime.now()
    
    def __exit__(self, *args, **kwargs):
        result = datetime.now() - self.start
        print("时间 -->", result)

with Keeptime():
    for i in range(100):
        pass

image.png

假如我又想拥有装饰器的那种功能,也不想丢失上下文管理计时的功能,如下代码: 了解即可。要想这里self.__wrapped__生效,就必须调用wraps(f)(self)。

from datetime import datetime
from functools import wraps  

class Keeptime:
    def __init__(self, f=None):
        print("f -->", f)
        wraps(f)(self)
        print("__wrapped__ -->", self.__wrapped__)

    def __call__(self, *args, **kwargs):
        start = datetime.now()
        test = self.__wrapped__(*args, **kwargs)
        result = datetime.now() - start
        print("call计时 -->", result)
        return test


    def __enter__(self):
        self.start = datetime.now()
    
    def __exit__(self, *args, **kwargs):
        result = datetime.now() - self.start
        print("时间 -->", result)

with Keeptime():
    for i in range(100):
        pass

@Keeptime
def delNum(a, b):
    return a - b

delNum(4, 1)

image.png

继续self.wrapped,当我没使用wraps前是没有__wrapped__,调用后才有的它。不太好理解,可以先写个简单的函数,然后打印出wraps使用前后的变化(wraps(函数)(类实例)),调用dir(xxx)查看结果就知道了。 image.png

2 总结

通过__init__和__call__也可以实现类似装饰器的计时功能,而且对上下文管理(它通常是写成一个类)的计时功能也不影响,相互不影响也就可以说明,我们既可以对函数装饰,也不放过对代码块的装饰,鱼和熊掌兼得之。应用场景:权限校验,插入日志之类的等。