理解Python中的装饰器之概念篇

中科荣膺公益中国 http://disease.39.net/yldt/bjzkbdfyy/6105611.html

装饰器在Python中是非常重要的概念,装饰器可以应用到各个场景中,它可以在不改变当前代码逻辑的情况下加一些额外功能,这篇我们从浅入深逐步讲解,第一步先了解什么是装饰器,然后我们逐步过渡到如何编写装饰器,最后我们怎么使用装饰器,因为篇幅较长,我打算分几篇去讲解,本篇我们先从概念说起。

什么是装饰器

装饰器是Python函数(或类)的包装器,它们改变了这些类的工作方式。Decorator表示法被设计为尽可能不对原函数或类进行修改。开发人员可以按照他的习惯在他的领域内开发他的代码,并且只使用装饰器来扩展功能。这听起来很抽象,所以让我们看一些例子。

在Python中,装饰器主要用于装饰函数(或方法)。也许,最常用的装饰器之一是

property装饰器:

classRectangle:def__init__(self,a,b):self.a=aself.b=b

propertydefarea(self):returnself.a*self.brect=Rectangle(5,6)print(rect.area)#30

就像在最后一行中看到的,你可以像访问属性一样访问Rectangle的area值,也就是说,你不必调用area方法。相反,当像属性一样访问区域时(没有()),由于

property装饰器,该方法被隐式调用。

它是如何工作的?

在函数定义前面写

property等价于写area=property(area)。换句话说:property是一个函数,它接受另一个函数作为参数并返回第三个函数。这正是装饰器所做的。

结果,装饰器改变了被装饰函数的行为。

编写自定义装饰器

有了这个模糊的定义,让我们编写自己的装饰器来了解它们是如何工作的。

假设我们有一个函数,如果它失败了,我们想重试。我们需要一个函数(我们的装饰器)调用我们的函数一次或两次(取决于它是否第一次失败)。

根据我们最初对装饰器的定义,我们可以这样写这个简单的装饰器:

defretry(func):def_wrapper(*args,**kwargs):try:func(*args,**kwargs)except:time.sleep(1)func(*args,**kwargs)return_wrapper

retrydefmight_fail():print("might_fail")raiseExceptionmight_fail()

retry是我们装饰器的名称,它接受任何函数作为参数(func)。在装饰器内部,定义并返回了一个新函数(_wrapper)。乍一看,在另一个函数中定义一个函数可能看起来有些陌生。然而,这在语法上非常好,并且我们的_wrapper函数仅在我们的retry装饰器的命名空间内有效。

请注意,在此示例中,我们仅使用

retry修饰了我们的函数。

retry装饰器后没有括号(())。因此,当调用我们的might_fail()函数时,会使用我们的函数(might_fail)作为第一个参数来调用retry装饰器。

总的来说,我们在这里处理三个函数:

retry

_wrapper

might_fail

在某些情况下,我们需要装饰器来接受参数。在我们的例子中,我们可以将重试次数作为参数。但是,装饰器必须将我们的装饰函数作为第一个参数。请记住,在用它装饰函数时,我们不需要调用我们的装饰器,即我们只是在装饰函数定义之前写了

retry,而不是

retry()。

装饰器只不过是一个函数(它接受另一个函数作为参数)

装饰器通过将其放在函数定义前面而不调用它来使用

因此,我们可以引入第四个函数,它接受我们想要的参数作为配置并返回一个实际上是装饰器的函数(它接受另一个函数作为参数)。

让我们试试这个:

defretry(max_retries):defretry_decorator(func):def_wrapper(*args,**kwargs):for_inrange(max_retries):try:func(*args,**kwargs)except:time.sleep(1)return_wrapperreturnretry_decorator

retry(2)defmight_fail():print("might_fail")raiseExceptionmight_fail()

代码分析:

在第一层,我们有一个叫做retry的函数。

retry接受任意参数(在我们的例子中为max_retries)并返回一个函数

retry_decorator是retry返回的函数,是我们实际的装饰器

_wrapper的工作方式与以前相同(它现在只增加了最大重试次数)

这是我们装饰器的定义。

may_fail这次被一个函数调用修饰,即

retry(2)。

retry(2)导致调用函数retry并返回实际的装饰器

might_fail最终由retry_decorator修饰,因为这个函数是retry(2)调用的结果。

定时器装饰器

这是另一个有用的装饰器示例:让我们创建一个装饰器来测量用它装饰的函数的运行时间。

importfunctoolsimporttimedeftimer(func):

functools.wraps(func)def_wrapper(*args,**kwargs):start=time.perf_counter()result=func(*args,**kwargs)runtime=time.perf_counter()-startprint(f"{func.__name__}took{runtime:.4f}secs")returnresultreturn_wrapper

timerdef


转载请注明:http://www.aierlanlan.com/rzgz/320.html

  • 上一篇文章:
  •   
  • 下一篇文章: 没有了