gpt4 book ai didi

python - 了解类装饰器在 Python 中的工作原理

转载 作者:太空宇宙 更新时间:2023-11-04 00:35:49 25 4
gpt4 key购买 nike

我在理解 Python 中类装饰器的工作原理时遇到了问题。在这种情况下,我想编写一个装饰器来计算调用递归函数(搜索最大公约数)的次数。我有一个装饰器:

class TrackCalls(object):

def __init__(self, func):
self.func = func
self.calls = 0

def __call__(self,*args,**kwargs):
self.calls += 1
return self.func(*args, **kwargs)

def called(self):
return self.calls

和一个函数:

@TrackCalls
def NWD(a, b):

if a > b:
return NWD(a-b, b)
elif b > a:
return NWD(a, b-a)
else:
return a

然后我给他们打电话:

print(NWD(60,25)) #5
print(NWD.called()) #6

NWD 函数到底发生了什么?据我所知,装饰器接受一个函数并创建另一个函数,所以在这种情况下 TrackCalls 接受函数,创建类 TrackCalls 的对象,然后通过调用 NWD.called() 我基本上调用了一个TrackCalls 对象的方法?当我运行时。 NWD(5,25) 在之前的调用之后我得到了 11,所以看起来每次我调用 NWD 时我都会用某种静态变量调用 TrackCalls 对象。如果我用同一个装饰器装饰另一个递归函数,它们会共享 calls 变量吗?

最佳答案

我认为你的困惑可以追溯到 python 的 duck-typing 概念。这是指从外部角度来看,函数 [我们称它为 func] 和对象 (=instance) [我们称它为 之间没有区别的想法>obj] 具有 __call__ 方法的类。两者都是 callable,也就是说它们可以在括号内接受参数并分别返回 func(args)obj(args) 中的内容。当然,区别在于对象 obj 具有状态,即它具有实例变量(通常也称为字段)。

在您的示例中,callsfuncTrackCalls 类的字段。通过使用 @TrackCalls 装饰您的 NWD 函数,您可以使用 TrackCalls实例 包装 NWD >。即名称 NWD 基本上替换为 TrackCalls 的实例,相当于调用 NWD = TrackCalls(NWD)。新实例是可调用的,因此其行为类似于原始函数,但由于它是一个对象,它也有状态并且可以计算其 __call__ 方法的调用。计算本身委托(delegate)给 NWD 的原始实现,它现在存储在 func 字段中。

要回答您的问题,您用 TrackCalls 修饰的每个函数都会产生一个新的 TrackCalls 实例,每个函数都有自己的 状态。但是对一个修饰函数的多次调用共享该函数的状态。

关于python - 了解类装饰器在 Python 中的工作原理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44096730/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com