gpt4 book ai didi

python - 计算对类和任何子类的某些方法的调用

转载 作者:太空宇宙 更新时间:2023-11-04 03:15:52 26 4
gpt4 key购买 nike

我有一个通用类,用户应该将其子类化以实现某些方法。可以有几个层次深的子类。有点像

class Thing(object):
def fun(self, *args, **kwargs):
raise NotImplementedError()

class Bell(Thing):
def fun(self):
return 1

class Whistle(Bell):
def fun(self):
return super(Whistle, self).fun() + 1

我想计算当使用 Thing 的任何子类时 fun() 被调用的次数。因为装饰器不是继承的,并且因为我不希望用户必须记住装饰他们的 fun() 方法,所以我的理解是元类是可行的方法。所以我写了

class CountCalls(type):

def __new__(cls, name, bases, attrs):
attrs["_original_fun"] = attrs["fun"]
attrs["fun"] = countcalls(attrs["_original_fun"])
return super(CountCalls, cls).__new__(cls, name, bases, attrs)

其中 countcalls 是计算调用次数的经典装饰器:

def countcalls(fn):
def wrapper(*args, **kwargs):
wrapper.ncalls += 1
return fn(*args, **kwargs)
wrapper.ncalls = 0
wrapper.__name__ = fn.__name__
wrapper.__doc__ = fn.__doc__
return wrapper

并将 Thing 的定义更改为

class Thing(object):

__metaclass__ = CountCalls

def fun(self, *args, **kwargs):
raise NotImplementedError()

问题:这可行,但它有意想不到的副作用,即当 fun() 调用任何实例的方法:

>>> b1 = Bell()
>>> b2 = Bell()
>>> b1.fun.ncalls, b2.fun.ncalls
(0, 0)
>>> b1.fun()
1
>>> b1.fun.ncalls, b2.fun.ncalls
(1, 1)

问题:如何计算每个实例对 fun() 的调用次数?感觉我应该在元类中实现 __init__ 而不是 __new__,但到目前为止我还没有找到正确的语法。例如,使用

def __init__(self, name, bases, attrs):
attrs["_original_fun"] = attrs["fun"]
attrs["fun"] = countcalls(attrs["_original_fun"])
super(CountCalls, self).__init__(name, bases, attrs)

产量

>>> b = Bell()
>>> b.fun.ncalls
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'function' object has no attribute 'ncalls'

谢谢!

最佳答案

你可以通过稍微改变你的继承模式来跳过元类:

class Thing(object):
def __init__(self):
self.fun_calls = 0

def fun(self, *args, **kwargs):
self.fun_calls += 1
self._fun(*args, **kwargs)

def _fun(self, *args, **kwargs):
raise NotImplementedError()

然后只需在您的子类中覆盖 _fun 即可。这使您可以按实例自动计数,并且它(imo)比元类实现更清晰,更易于理解。

关于python - 计算对类和任何子类的某些方法的调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36319757/

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