查看原文
其他

推荐 8 个炫酷的 Python 装饰器

点击上方 "Python人工智能技术关注,星标或者置顶
22点24分准时推送,第一时间送达
后台回复“大礼包”,送你特别福利

编辑:乐乐 | 来自:Python数据分析实例

Pythn人工智能技术(ID:coder_experience)第649期推文

上一篇:大学生上“暗网”发现“财富密码”,结果…


正文


大家好,我是Pythn人工智能技术。

前言


Python 编程语言的一大优点是它把所有功能都打包到一个小包中,这些功能非常有用。


许多特性可以完全改变 Python 代码的功能,这使得该语言更加灵活。如果使用得当,其中一些功能可以有效缩短编写程序所需的时间。


实现这些目标的一个很好的例子是 Python 的装饰器。


00装饰器


装饰器(decorators)是一个可以用于改变一个 Python 函数对象行为的函数。它们可以应用于类和函数,可以做很多非常有趣的事情!
装饰器可以用来缩短代码、加速代码并彻底改变代码在 Python 中的行为方式。
不用说,这当然可以派上用场!今天我想炫耀一些我认为值得一试的装饰器。
有很多装饰器,但我选择了一些我认为具有最酷功能的装饰器。


01@lru_cache


此列表中的第一个装饰器来自 functools 模块。
该模块包含在标准库中,非常易于使用。它还包含比这个装饰器更酷的功能,但这个装饰器肯定是我最喜欢的。
此装饰器可用于使用缓存加速函数的连续运行。当然,这应该在使用时记住一些关于缓存的注意事项,但在通用使用情况下,大多数时候这个装饰器是值得使用的。
能够用一个简单的装饰器来加速代码是非常棒的。
可以从这样的装饰器中受益的函数的一个很好的例子是递归函数,例如计算阶乘的函数:
def factorial(n): return n * factorial(n-1) if n else 1
递归在计算时间上可能非常困难,但添加此装饰器有助于显着加快此函数的连续运行速度。
@lru_cachedef factorial(n): return n * factorial(n-1) if n else 1
现在每当我们运行这个函数时,前几个阶乘计算将被保存到缓存中。
因此,下次我们调用该函数时,我们只需要计算我们之前使用的阶乘之后的阶乘。
当然,并不是所有的阶乘计算都会被保存,但是很容易理解为什么这个装饰器的一个很好的应用程序来加速一些自然很慢的代码。
02@jit


JIT 是即时编译(Just In Time)的缩写。通常每当我们在 Python 中运行一些代码时,发生的第一件事就是编译。
这种编译会产生一些开销,因为类型被分配了内存,并存储为未分配但已命名的别名。使用即时编译,我们在执行时才进行编译。
在很多方面,我们可以将其视为类似于并行计算的东西,其中 Python 解释器同时处理两件事以节省一些时间。
Numba JIT 编译器因将这一概念提供到 Python 中而闻名。与@lru_cache 类似,可以非常轻松地调用此装饰器,并立即提高代码的性能。Numba 包提供了 jit 装饰器,它使运行更密集的软件变得更加容易,而不必进入 C。
以下案例使用@jit 装饰器加速蒙特卡洛方法计算。
from numba import jitimport 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
03@do_twice


do_twice 装饰器的功能与它的名字差不多。此装饰器可用于通过一次调用运行两次函数。这当然有一些用途,我发现它对调试特别有用。
它可以用于测量两个不同迭代的性能。以 Functools 为例,我们可以让一个函数运行两次,以检查是否有改进。该函数由 Python 中的装饰器模块提供,该模块位于标准库中。
from decorators import do_twice@do_twicedef timerfunc():%timeit factorial(15)
04@count_calls


count_calls 装饰器可用于提供有关函数在软件中使用多少次的信息。
像 do_twice 一样,这当然可以在调试时派上用场。
当添加到给定的函数时,我们将收到一个输出,告诉我们该函数每次运行时已经运行了多少次。这个装饰器也在标准库的装饰器模块中。
from decorators import count_calls@count_callsdef function_example():print("Hello World!") function_example()function_example()function_example()
05@dataclass


为了节省编写类的时间,我一直使用的最好的装饰器之一是@dataclass 装饰器。
这个装饰器可用于快速编写类中常见的标准方法,这些方法通常会在我们编写的类中找到。
这个装饰器来自 dataclass 模块。这个模块也在标准库中,所以不需要 PIP 来尝试这个例子!
from dataclasses import dataclass
@dataclassclass Food:name: strunit_price: floatstock: int = 0
def stock_value(self) -> float: return(self.stock * self.unit_price)
这段代码将自动创建一个初始化函数 init(),其中包含填充类中数据所需的位置参数。
它们也将自动提供给 self,因此无需编写一个很长的函数来将一些数据参数放入类中。
06@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
@singletonclass cls:def func(self):
另一种方法是使用元类!
07@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_unitreturn decorator_use_unit
@use_unit("meters per second")def average_speed(distance, duration):return distance / duration
08@singledispatch


Functools 凭借非常有用的@singledispatch 装饰器再次在此列表中脱颖而出。
单调度是一种编程技术,在许多编程语言中都很常见,因为它是一种非常棒的编程方式。虽然我更喜欢多调度,但我认为单调度可以在很多方面扮演相同的角色。
这个装饰器使得在 Python 中使用多类型数据变得更加容易, 尤其当我们希望通过同一方法传递多种类型数据时,情况更是如此。
@singledispatchdef fun(arg, verbose=False):if verbose:print("Let me just say,", end=" ")print(arg)
@fun.registerdef \_(arg: int, verbose=False):if verbose:print("Strength in numbers, eh?", end=" ")print(arg)
@fun.registerdef \_(arg: list, verbose=False):if verbose:print("Enumerate this:")for i, elem in enumerate(arg):print(i, elem)
你还有什么想要补充的吗?

免责声明:本文内容来源于网络,文章版权归原作者所有,意在传播相关技术知识&行业趋势,供大家学习交流,若涉及作品版权问题,请联系删除或授权事宜。


技术君个人微信


添加技术君个人微信即送一份惊喜大礼包


→ 技术资料共享

→ 技术交流社群



--END--


往日热文:

iOS 15 成用户隐私“照妖镜”?美团、QQ 等 APP 纷纷“现形”

10个Python图像处理工具随你选

韦东奕陈杲同获达摩院青橙奖,90后数学新星光彩夺目,却说「没有黄金一代」

68 个 Python 内置函数详解,进阶必备


Python程序员深度学习的“四大名著”:



这四本书着实很不错!我们都知道现在机器学习、深度学习的资料太多了,面对海量资源,往往陷入到“无从下手”的困惑出境。而且并非所有的书籍都是优质资源,浪费大量的时间是得不偿失的。给大家推荐这几本好书并做简单介绍。


获得方式:

1.扫码关注本公众号
2.后台回复关键词:名著

▲长按扫描关注,回复名著即可获取

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存