超棒!这 8 个 Python 装饰器值得一试!

Python 编程语言的一大优点是它把所有功能都打包到一个小包中,这些功能非常有用。许多特性改变了 Python 代码,使得该语言更加灵活。如果使用得当,一些功能可以有效缩短编写程序所需的时间。

要实现这些目标的一个很好的例子就是 Python 的装饰器。今天我们详细聊一下它,欢迎收藏学习,喜欢点赞支持。文末提供技术交流群

装饰器是什么?

装饰器(decorators)是一个可以用于改变一个 Python 函数对象行为的函数。它们可以应用于类和函数,可以做很多非常有趣的事情!

装饰器可以用来缩短代码、加速代码并彻底改变代码在 Python 中的行为方式。

今天我想炫耀一些我认为值得一试的装饰器。


1、@lru_cache

此列表中的第一个装饰器来自 functools 模块。

该模块包含在标准库中,非常易于使用。它还包含比这个装饰器更酷的功能,但这个装饰器肯定是我最喜欢的。

此装饰器可用于使用缓存加速函数的连续运行。当然,这应该在使用时记住一些关于缓存的注意事项,但在通用使用情况下,大多数时候这个装饰器是值得使用的。

能够用一个简单的装饰器来加速代码是非常棒的。

可以从这样的装饰器中受益的函数的一个很好的例子是递归函数,例如计算阶乘的函数:

def factorial(n):
    return n * factorial(n-1) if n else 1

递归在计算时间上可能非常困难,但添加此装饰器有助于显着加快此函数的连续运行速度。

@lru_cache
def factorial(n):
    return n * factorial(n-1) if n else 1

现在每当我们运行这个函数时,前几个阶乘计算将被保存到缓存中。

因此,下次我们调用该函数时,我们只需要计算我们之前使用的阶乘之后的阶乘。

当然,并不是所有的阶乘计算都会被保存,但是很容易理解为什么这个装饰器的一个很好的应用程序来加速一些自然很慢的代码。

2、@jit


JIT 是即时编译(Just In Time)的缩写。通常每当我们在 Python 中运行一些代码时,发生的第一件事就是编译。

这种编译会产生一些开销,因为类型被分配了内存,并存储为未分配但已命名的别名。使用即时编译,我们在执行时才进行编译。

在很多方面,我们可以将其视为类似于并行计算的东西,其中 Python 解释器同时处理两件事以节省一些时间。

Numba JIT 编译器因将这一概念提供到 Python 中而闻名。与@lru_cache 类似,可以非常轻松地调用此装饰器,并立即提高代码的性能。Numba 包提供了 jit 装饰器,它使运行更密集的软件变得更加容易,而不必进入 C。

以下案例使用@jit 装饰器加速蒙特卡洛方法计算。

from numba import jit
import random

@jit(nopython=True)
def monte_carlo_pi(nsamples):
    acc = 0
    for i in range(nsamples):
        x = random.random()
        y = random.random()
        if (x ** 2 + y ** 2) < 1.0:
            acc += 1
    return 4.0 * acc / nsamples

3、@do_twice


do_twice 装饰器的功能与它的名字差不多。此装饰器可用于通过一次调用运行两次函数。这当然有一些用途,我发现它对调试特别有用。

它可以用于测量两个不同迭代的性能。以 Functools 为例,我们可以让一个函数运行两次,以检查是否有改进。该函数由 Python 中的装饰器模块提供,该模块位于标准库中。

from decorators import do_twice
@do_twice
def timerfunc():
%timeit factorial(15)

4、@count_calls

count_calls 装饰器可用于提供有关函数在软件中使用多少次的信息。

像 do_twice 一样,这当然可以在调试时派上用场。

当添加到给定的函数时,我们将收到一个输出,告诉我们该函数每次运行时已经运行了多少次。这个装饰器也在标准库的装饰器模块中。

from decorators import count_calls
@count_calls
def function_example():
print("Hello World!")
  
function_example()
function_example()
function_example()

5、@dataclass

为了节省编写类的时间,我一直使用的最好的装饰器之一是@dataclass 装饰器。

这个装饰器可用于快速编写类中常见的标准方法,这些方法通常会在我们编写的类中找到。

这个装饰器来自 dataclass 模块。这个模块也在标准库中,所以不需要 PIP 来尝试这个例子!

from dataclasses import dataclass

@dataclass
class Food:
name: str
unit_price: float
stock: int = 0

    def stock_value(self) -> float:
        return(self.stock * self.unit_price)

这段代码将自动创建一个初始化函数 init(),其中包含填充类中数据所需的位置参数。

它们也将自动提供给 self,因此无需编写一个很长的函数来将一些数据参数放入类中。

6 、@singleton

为了理解单例装饰器的用途,我们首先需要了解单例(singleton)是什么。从某种意义上说,单例是全局变量类型的一个版本。

这意味着类型被定义为只存在一次。尽管这些在 C++ 等语言中很常见,但在 Python 中却很少见到。使用单例,我们可以创建一个只使用一次的类并改变类,而不是通过初始化来构造新的类型。

通常,单例装饰器是由用户自己编写的,实际上并不是导入的。

这是因为单例仍然是对我们单例装饰器中提供的模板的引用。我们可以命名一个单例函数并编写一个包装器,以便在我们的类上使用这个装饰器:

def singleton(cls):
instances = {}
def wrapper(*args, \*\*kwargs):
if cls not in instances:
instances[cls] = cls(*args, \*\*kwargs)
return instances[cls]
return wrapper

@singleton
class cls:
def func(self):

另一种方法是使用元类!

class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]
        
class Logger(object):
    __metaclass__ = Singleton

7、@use_unit

在科学计算中经常派上用场的一种装饰器是 @use_unit 装饰器。

此装饰器可用于更改返回结果的表示单位。这对于那些不想在数据中添加度量单位但仍希望人们知道这些单位是什么的人很有用。

这个装饰器也不是在任何模块中真正可用,但它是非常常见的,对科学应用程序非常有用。

def use_unit(unit):
    """Have a function return a Quantity with given unit"""
    use_unit.ureg = pint.UnitRegistry()
    def decorator_use_unit(func):
        @functools.wraps(func)
        def wrapper_use_unit(*args, **kwargs):
            value = func(*args, **kwargs)
            return value * use_unit.ureg(unit)
        return wrapper_use_unit
    return decorator_use_unit

@use_unit("meters per second")
def average_speed(distance, duration):
    return distance / duration

8、 @singledispatch


Functools 凭借非常有用的@singledispatch 装饰器再次在此列表中脱颖而出。

单调度是一种编程技术,在许多编程语言中都很常见,因为它是一种非常棒的编程方式。虽然我更喜欢多调度,但我认为单调度可以在很多方面扮演相同的角色。

这个装饰器使得在 Python 中使用多类型数据变得更加容易, 尤其当我们希望通过同一方法传递多种类型数据时,情况更是如此。

@singledispatch
def fun(arg, verbose=False):
        if verbose:
            print("Let me just say,", end=" ")
        print(arg)
@fun.register
def _(arg: int, verbose=False):
    if verbose:
        print("Strength in numbers, eh?", end=" ")
    print(arg)
@fun.register
def _(arg: list, verbose=False):
    if verbose:
        print("Enumerate this:")
    for i, elem in enumerate(arg):
        print(i, elem)

参考链接:https://towardsdatascience.com/10-fabulous-python-decorators-ab674a732871


技术交流

欢迎转载、收藏、有所收获点赞支持一下!

在这里插入图片描述

目前开通了技术交流群,群友已超过2000人,添加时最好的备注方式为:来源+兴趣方向,方便找到志同道合的朋友

  • 方式①、发送如下图片至微信,长按识别,后台回复:加群;
  • 方式②、添加微信号:dkl88191,备注:来自CSDN
  • 方式③、微信搜索公众号:Python学习与数据挖掘,后台回复:加群

长按关注

您可以使用以下代码来搜索多个关键字: ```python import re # 输入关键字 keywords = input('keywords: ').split() # 文本内容 text = "这是一段文本内容,包含了一些关键字。" # 使用正则表达式搜索关键字 for keyword in keywords: pattern = re.compile(keyword) result_search = pattern.search(text) if result_search: print("关键字:", keyword, "在文本中被找到。") else: print("关键字:", keyword, "在文本中未找到。") ``` 这段代码首先使用`input()`函数获取用户输入的关键字,并使用`split()`方法将其分割成一个关键字列表。然后,通过正则表达式的`search()`方法在文本中搜索每个关键字。如果找到了关键字,则打印出关键字在文本中被找到的信息;如果未找到,则打印出关键字在文本中未找到的信息。 #### 引用[.reference_title] - *1* *3* [【Python】用 Python 从单个文本中提取关键字的四种超棒的方法](https://blog.csdn.net/fengdu78/article/details/124207184)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Python 文本匹配关键词,多个关键词从文本中匹配,疾病关键词匹配,.findall () .match() .search()的区别和应用实例,医学文本关键词检索](https://blog.csdn.net/L_goodboy/article/details/124321540)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值