python 音速_[经验漫谈]Python装饰器函数如何改变内部属性

当你发现自己是周遭一群人中最聪明的那一个,说明你该换个圈子了

by Volsky Surd(沃兹各 硕德)

注意:本篇内容较为深奥,不建议使用Python经验较少的用户阅读

    当你阅读了文章标题可能会感到困惑,本文讲述的内容涉及什么样的场景。本文涉及的场景比较罕见,简单地说,就是你要定义一个装饰器,这个装饰器需要在运行时提供调整自身行为的接口。如果你还没懂的话,不必纠结在此处,继续阅读下去就好了。

    我在此处设定了一个具体场景,你可能不知道,Python在某些情况之下,进行哪怕最简单的数学运算也可能出现错误。比如你手头有电脑的话可以试试2.2+0.2。不同机器运行的结果不知道会不会有差异,在我的机器上(openSUSE leap 15.2 CPython3.7.7)结果如下

51680d77df0014303915658c689f9724.png

    如何规避这个问题呢,简单来说,你并不一定非得规避这个问题,除非你是干金融之类的,差一分钱都不行那种。属实要进行精确运算的话,可以使用decimal库,没记错的话,这是Python标准库之一。但是此库使用的话会降低程序运行效率,我相信一般行业不会想为了提高这么点精度而选择拖慢程序速度。更具体的东西本文不涉及,接下来我搞一个可以指定计算精度高低的装饰器,直接上代码。

from decimal import Decimalfrom functools import wraps, partialdef add_attr_wrapper(obj, func=None):    """装饰器,用于为obj添加一个函数func作为属性"""    if func is None:        return partial(add_attr_wrapper, obj)    setattr(obj, func.__name__, func)    return funcdef calc_precision(func=None, precision="high"):    """指定数学运算的精度"""    if func is None:        return partial(calc_precision, precision=precision)    print(f"正在执行{func.__name__}函数")    @wraps(func)    def inner(*args, **kwargs):        print(f"将以{precision}精度计算")        if precision == "high":            # 如果指定了高精度运算,则使用decimal运算            # 只需此前将常规浮点数转换成decimal中的数            args = [Decimal(str(arg)) for arg in args]        res = func(*args, **kwargs)        return float(res)  # 将运算结果转换成常规浮点数,方便使用    @add_attr_wrapper(inner)    def set_precision(new_precision):        # 精髓在这,为装饰后的对象添加这个接口,可以在程序运行时改变计算精度        nonlocal precision        precision = new_precision    return inner

有了这个,下一步就是将装饰器应用在函数上

@calc_precision(precision="norm")  # 此处指定默认以常规精度运算def add(x, y):    return x + yif __name__ == "__main__":    result = add(2.2, .2)    print(result)    add.set_precision("high")  # 此时改以高精度运算    result = add(2.2, .2)    print(result)    add.set_precision("norm")    result = add(2.2, .2)    print(result)

我们可以用用看效果

4a86b0a71399cab8700984e3f51170d5.png

    下面我来做一点简单讲解,如果没有29-33(作为文科生,提到这两个数马上想起了经济大萧条0a2ee88de40601f9fd31e367a1132624.png)行代码,这里calc_precision只是一个普通的装饰器,29-33行添加了运行时修改内部设定的行为,这里将precision属性做了修改。而29-33行可以生效要依靠5-10行的add_attr_wrapper装饰器,将可以修改calc_precision内部设定的set_precision函数开放给用户访问,妙啊。

    如果看不懂没有关系,这类使用场景相当罕见,就连笔者自己都没有遇见过。我不得不承认,如果遇见了的话也得把这篇文章翻出来扒代码使,这种事情当你知道可以从哪里直接拿现成的东西来用的话,就没有必要记住它,爱因斯坦连音速多少都记不得,他说

“[I do not] carry such information in my mind since it is readily available in books.”,我完全认同。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值