高阶装饰器

lru_cache和singledispatch

functools.wraps

functools.wraps 是Python标准库中拿来即用的装饰器之一。虽然这不是这篇文章的重点,但还是举个例子:

def clock(func):
    time0 = time.time()

    @functools.wraps(func)
    def clocked(*args, **kwargs):
        t0 = time.time()
        result = func(*args, **kwargs)
        elapsed = time.time() - t0
        name = func.__name__
        arg_lst = []
        if args:
            arg_lst.append(', '.join(repr(arg) for arg in args))
        if kwargs:
            pairs = ['%s=%r' % (k, w) for k, w in sorted(kwargs.items())]
            arg_lst.append(', '.join(pairs))
        arg_str = ', '.join(arg_lst)
        print('[{:.8f}] {}({}) -> {}'.format(elapsed, name, arg_str, result))
        return result
    time1 = time.time()
    print('{:.5f}'.format(time1-time0))
    return clocked

在这里,@functools.wraps()里面传入的func就是被这个装饰器包装的函数,在使用时调用这个装饰器即可。

functools.lru_cache

functools.lru_cache是非常实用的装饰器,它实现了备忘功能。这是一项优化技术,它把耗时的函数结果保存起来,避免传入相同的参数时的重复计算。
LRU三个字母是“Least Recently Used”的缩写,表明缓存不会无限增长,一段时间不用的缓存条目会被扔掉。我们现在来实现一个斐波拉契数列:

@clock
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-2) + fibonacci(n-1)
if __name__=='__main__':
    print(fibonacci(6))

运行结果:

0.00002
[0.00000119] fibonacci(0) -> 0
[0.00000095] fibonacci(1) -> 1
[0.00004601] fibonacci(2) -> 1
[0.00000000] fibonacci(1) -> 1
[0.00000000] fibonacci(0) -> 0
[0.00000095] fibonacci(1) -> 1
[0.00002813] fibonacci(2) -> 1
[0.00005388] fibonacci(3) -> 2
[0.00013494] fibonacci(4) -> 3
[0.00000095] fibonacci(1) -> 1
[0.00000119] fibonacci(0) -> 0
[0.00000072] fibonacci(1) -> 1
[0.00002599] fibonacci(2) -> 1
[0.00005198] fibonacci(3) -> 2
[0.00000000] fibonacci(0) -> 0
[0.00000072] fibonacci(1) -> 1
[0.00006986] fibonacci(2) -> 1
[0.00000000] fibonacci(1) -> 1
[0.00000000] fibonacci(0) -> 0
[0.00000000] fibonacci(1) -> 1
[0.00002813] fibonacci(2) -> 1
[0.00005603] fibonacci(3) -> 2
[0.00015402] fibonacci(4) -> 3
[0.00022912] fibonacci(5) -> 5
[0.00039196] fibonacci(6) -> 8
8

我们可以看到在这行这个函数的时候大部分时间都是装饰器在执行重复的操作,如果我们把装饰器的操作缓存起来就会有更好的体验。

@functools.lru_cache() # 这里引入缓存,实现更高的执行速度
@clock
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n - 2) + fibonacci(n - 1)


if __name__ == '__main__':
    print(fibonacci(6))

执行结果:

0.00002
[0.00000000] fibonacci(0) -> 0
[0.00000000] fibonacci(1) -> 1
[0.00002813] fibonacci(2) -> 1
[0.00000095] fibonacci(3) -> 2
[0.00004625] fibonacci(4) -> 3
[0.00000095] fibonacci(5) -> 5
[0.00006390] fibonacci(6) -> 8
8

可以看到这个函数的执行过程大大减少了,虽然执行时间变化很小(这里只取了5位小数位,差别并不明显),那是因为这里只是生成了6次的斐波拉切数,如果是100次,
差别会是非常非常大的。

另外有几个注意的地方:

  1. functools.lru_cache()有两个参数,签名是functools.lru_cache(maxsize=128, typed=False)maxsize指定存储多少个调用的结果,缓存满了之后,旧的结果会被扔掉,腾出显得空间。为了得到最佳的性能,maxsize应该设为2的幂,默认为128。如果设置为None的话就相当于是maxsize为正无穷。type参数设为True,会把不同类型的结果分开保存,即把通常认为想等的浮点数和整数类型(如1和1.0)区分。

  2. 因为lru_cache使用字典存储结果,而且键根据传入的定位参数和关键字参数创建,所以被lru_cache装饰的函数,它的所有参数必须是可散列的。

  3. lru_cache装饰的函数会有cache_clearcache_info两个方法,分别用于清除缓存和查看缓存信息

除了优化递归算法之外,lru_cache在从Web中获取信息的应用中也能发挥巨大作用。

functools.singledispatch

因为Python不支持方法的重载,在Pyhon3.4版本之后新增了functools.singledispatch装饰器,它可以把整体方案拆分成多个模块,甚至可以为你无法修改的
类提供专门的函数。使用@singledispatch装饰的普通函数会变成泛函数(generic function):根据第一个参数的类型,以不同的方式执行相同操作的一组函数。
采用Python官方文档的例子:

from decimal import Decimal
from functools import singledispatch


@singledispatch
def fun(arg, verbose=False):
    if verbose:
        print("Let me just say,", end=" ")
    print(arg)


@fun.register(int) # 各个函数专门使用@«base_function».register(«type»)装饰
def _(arg, verbose=False):
    if verbose:
        print("Strength in numbers, eh?", end=" ")
    print(arg)


@fun.register(list)
def _(arg, verbose=False):
    if verbose:
        print("Enumerate this:")
    for i, elem in enumerate(arg):
        print(i, elem)


@fun.register(float)
@fun.register(Decimal)
def fun_num(arg, verbose=False):
    if verbose:
        print("Half of your number:", end=" ")
    print(arg / 2)


def nothing(arg, verbose=False):
    print("Nothing.")


fun.register(type(None), nothing) # 另一种注册的方式

if __name__ == '__main__':
    fun("hello,world")
    fun("test.", verbose=True)
    fun(42, verbose=True)
    fun(['spam', 'spam', 'eggs', 'spam'], verbose=True)
    fun(None)
    fun(1.23)

执行结果:

hello,world
Let me just say, test.
Strength in numbers, eh? 42
Enumerate this:
0 spam
1 spam
2 eggs
3 spam
Nothing.
0.615

singledispatch是经过深思熟虑之后才添加到标准库中的,它提供的特性很多。它不是为了把Java中的重载带入Python,在一个类中为同一个方法定义多个重载
变体,比在一个函数中使用一长串if/elif/elif/else块要好。但是这两种方法都有一定的缺陷,因为他们让代码单元(类或者函数)承担的职责太多。@singledispatch的优点是支持模块化扩展;各个模块可以为他支持的各个类型注册一个专门的函数。

当然,除了上面的三种以外还有:
functools.property: 将方法装饰成属性;
functools.classmethod: 装饰成类方法;
functools.staticmethod : 装饰成静态方法.

参数化装饰器

解析源码的装饰器时,Python把被装饰的函数作为第一个参数传给装饰器函数。那怎么让装饰器接受其他函数呢?答案是:创建一个装饰器工厂函数,把参数传给他,返回

一个装饰器,然后再把它应用到要装饰的函数上。

为了便于启动或禁用register执行的函数执行注册功能,我们为他提供一个可选的activate参数,设为False时,不注册被修饰的函数。从概念上看,这个新的register函数不是装饰器,而是装饰器工厂函数。调用它会返回真正的装饰器,这才是应用到目标函数上的装饰器。

为了接受参数,新的register装饰器必须作为函数调用

registry = set()


def register(active=True): # 接受一个可选的关键字参数
    def decorate(func): # 这个内部函数是真正的装饰器,它的参数是一个函数
        print('running register(active=%s)->decorate(%s)'
              % (active, func))
        if active:
            registry.add(func)
        else:
            registry.discard(func) # 如果集合中存在该元素则删除,else do nothing
        return func # 注意,这里没有带括号,不会执行这个函数
    return decorate # register是装饰器工厂函数,因此返回decorate


@register(active=False) # 工厂函数必须作为函数调用,并且传入所需的参数
def f1():
    print('running f1()')


@register() # 即使不传入参数,register也必须作为函数调用,即要返回真正的装饰器decorate
def f2():
    print('running f2()')


def f3():
    print('running f3()')

执行结果:

running register(active=False)->decorate(<function f1 at 0x109a9e158>)
running register(active=True)->decorate(<function f2 at 0x109a9e048>)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
VR(Virtual Reality)即虚拟现实,是一种可以创建和体验虚拟世界的计算机技术。它利用计算机生成一种模拟环境,是一种多源信息融合的、交互式的三维动态视景和实体行为的系统仿真,使用户沉浸到该环境中。VR技术通过模拟人的视觉、听觉、触觉等感觉器官功能,使人能够沉浸在计算机生成的虚拟境界中,并能够通过语言、手势等自然的方式与之进行实时交互,创建了一种适人化的多维信息空间。 VR技术具有以下主要特点: 沉浸感:用户感到作为主角存在于模拟环境中的真实程度。理想的模拟环境应该使用户难以分辨真假,使用户全身心地投入到计算机创建的三维虚拟环境中,该环境中的一切看上去是真的,听上去是真的,动起来是真的,甚至闻起来、尝起来等一切感觉都是真的,如同在现实世界中的感觉一样。 交互性:用户对模拟环境内物体的可操作程度和从环境得到反馈的自然程度(包括实时性)。例如,用户可以用手去直接抓取模拟环境中虚拟的物体,这时手有握着东西的感觉,并可以感觉物体的重量,视野中被抓的物体也能立刻随着手的移动而移动。 构想性:也称想象性,指用户沉浸在多维信息空间中,依靠自己的感知和认知能力获取知识,发挥主观能动性,寻求解答,形成新的概念。此概念不仅是指观念上或语言上的创意,而且可以是指对某些客观存在事物的创造性设想和安排。 VR技术可以应用于各个领域,如游戏、娱乐、教育、医疗、军事、房地产、工业仿真等。随着VR技术的不断发展,它正在改变人们的生活和工作方式,为人们带来全新的体验。
VR(Virtual Reality)即虚拟现实,是一种可以创建和体验虚拟世界的计算机技术。它利用计算机生成一种模拟环境,是一种多源信息融合的、交互式的三维动态视景和实体行为的系统仿真,使用户沉浸到该环境中。VR技术通过模拟人的视觉、听觉、触觉等感觉器官功能,使人能够沉浸在计算机生成的虚拟境界中,并能够通过语言、手势等自然的方式与之进行实时交互,创建了一种适人化的多维信息空间。 VR技术具有以下主要特点: 沉浸感:用户感到作为主角存在于模拟环境中的真实程度。理想的模拟环境应该使用户难以分辨真假,使用户全身心地投入到计算机创建的三维虚拟环境中,该环境中的一切看上去是真的,听上去是真的,动起来是真的,甚至闻起来、尝起来等一切感觉都是真的,如同在现实世界中的感觉一样。 交互性:用户对模拟环境内物体的可操作程度和从环境得到反馈的自然程度(包括实时性)。例如,用户可以用手去直接抓取模拟环境中虚拟的物体,这时手有握着东西的感觉,并可以感觉物体的重量,视野中被抓的物体也能立刻随着手的移动而移动。 构想性:也称想象性,指用户沉浸在多维信息空间中,依靠自己的感知和认知能力获取知识,发挥主观能动性,寻求解答,形成新的概念。此概念不仅是指观念上或语言上的创意,而且可以是指对某些客观存在事物的创造性设想和安排。 VR技术可以应用于各个领域,如游戏、娱乐、教育、医疗、军事、房地产、工业仿真等。随着VR技术的不断发展,它正在改变人们的生活和工作方式,为人们带来全新的体验。
基于GPT-SoVITS的视频剪辑快捷配音工具 GPT, 通常指的是“Generative Pre-trained Transformer”(生成式预训练转换器),是一个在自然语言处理(NLP)领域非常流行的深度学习模型架构。GPT模型由OpenAI公司开发,并在多个NLP任务上取得了显著的性能提升。 GPT模型的核心是一个多层Transformer解码器结构,它通过在海量的文本数据上进行预训练来学习语言的规律。这种预训练方式使得GPT模型能够捕捉到丰富的上下文信息,并生成流畅、自然的文本。 GPT模型的训练过程可以分为两个阶段: 预训练阶段:在这个阶段,模型会接触到大量的文本数据,并通过无监督学习的方式学习语言的结构和规律。具体来说,模型会尝试预测文本序列中的下一个词或短语,从而学习到语言的语法、语义和上下文信息。 微调阶段(也称为下游任务训练):在预训练完成后,模型会被应用到具体的NLP任务中,如文本分类、机器翻译、问答系统等。在这个阶段,模型会使用有标签的数据进行微调,以适应特定任务的需求。通过微调,模型能够学习到与任务相关的特定知识,并进一步提高在该任务上的性能。 GPT模型的优势在于其强大的生成能力和对上下文信息的捕捉能力。这使得GPT模型在自然语言生成、文本摘要、对话系统等领域具有广泛的应用前景。同时,GPT模型也面临一些挑战,如计算资源消耗大、训练时间长等问题。为了解决这些问题,研究人员不断提出新的优化方法和扩展模型架构,如GPT-2、GPT-3等,以进一步提高模型的性能和效率。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值