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

标签 python metaclass

我有一个通用类,用户应该对其进行子类化以实现某些方法。可以有几个深度的子类。类似的东西

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 即可。这可以让你对每个实例进行自动计数,并且它(我认为)比元类实现更干净、更容易理解。

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

相关文章:

python - 将 dtype ='<U77' 类型的对象转换为 numpy 数组

grails - Groovy MetaClass-将类别方法添加到适当的metaClasses

python - 实现 python 元类来更改类级别变量

python - 查找在 Python 中重新定义之前使用的 __metaclass__

python - 使用元类允许前向声明

python - ctypes 和构建元类 : TypeError: *class* instance instead of LP_*class* instance

python - YAML:如何解释映射序列

python - 如何使用字典执行多个函数?

python - 我如何将数据发送到另一个程序并得到它的答案?

python - 从 matplotlib 导入 ft2font : "ImportError: DLL load failed: The specified procedure could not be found."