使用两个不同的装饰器实现装饰所有类方法的元类

2024-04-26 08:00:45 发布

您现在位置:Python中文网/ 问答频道 /正文

我在这个元类decorator中应用的decorator的实现有一个问题,我写道:

def decorateAll(decorator):
    class MetaClassDecorator(type):

        def __new__(meta, classname, supers, classdict):
            for name, elem in classdict.items():
                if type(elem) is FunctionType:
                    classdict[name] = decorator(classdict[name])
            return type.__new__(meta, classname, supers, classdict)
    return MetaClassDecorator

这是我在其中使用元类的类:

^{pr2}$

当我把decorate元类传递给decorate元类时,一切似乎都很好,一个decorator实现如下:

def Counter(fun):
    fun.count = 0
    def wrapper(*args):
        fun.count += 1
        print("{0} Executed {1} times".format(fun.__name__, fun.count))
        return fun(*args)
    return wrapper

但是当我使用这样实现的decorator时:

class Counter():

    def __init__(self, fun):
        self.fun = fun
        self.count = 0

    def __call__(self, *args, **kwargs):
        print("args:", self, *args, **kwargs)
        self.count += 1
        print("{0} Executed {1} times".format(self.fun.__name__, self.count))
        return self.fun(*args, **kwargs)

我有个错误:

line 32, in __call__
return self.fun(*args, **kwargs)
TypeError: __init__() missing 1 required positional argument: 'initial_amount'

为什么?将两个decorators实现与others函数一起使用不会给我带来问题。我认为问题与我试图修饰的方法是类方法这一事实有关。我错过什么了吗?在


Tags: nameselfnewreturndeftypecountargs
1条回答
网友
1楼 · 发布于 2024-04-26 08:00:45

您需要将Counter实现为可调用描述符。在描述符上执行__get__时,模拟将描述符绑定到传递给它的实例。另外,基于每个方法/对象存储计数。在

此代码:

import collections
import functools
import types


def decorateAll(decorator):
    class MetaClassDecorator(type):

        def __new__(meta, classname, supers, classdict):
            for name, elem in classdict.items():
                if type(elem) is types.FunctionType:
                    classdict[name] = decorator(classdict[name])
            return type.__new__(meta, classname, supers, classdict)
    return MetaClassDecorator


class Counter(object):
    def __init__(self, fun):
        self.fun = fun
        self.cache = {None: self}
        self.count = collections.defaultdict(int)

    def __get__(self, obj, cls=None):
        if obj is None:
            return self

        try:
            return self.cache[obj]
        except KeyError:
            pass

        print('Binding {} and {}'.format(self.fun, obj))
        cex = self.cache[obj] = functools.partial(self.__call__, obj)
        return cex

    def __call__(self, obj, *args, **kwargs):
        print("args:", obj, *args, **kwargs)
        self.count[obj] += 1
        print("{0} Exec {1} times".format(self.fun.__name__, self.count[obj]))
        return self.fun(obj, *args, **kwargs)


class Account(object, metaclass=decorateAll(Counter)):

    def __init__(self, initial_amount):
        self.amount = initial_amount

    def withdraw(self, towithdraw):
        self.amount -= towithdraw

    def deposit(self, todeposit):
        self.amount += todeposit

    def balance(self):
        return self.amount


a = Account(33.5)

print(a.balance())

生成以下输出:

^{pr2}$

它调用描述符的__call__方法,通过模拟创建functools.partial类型的对象的绑定,将计数存储在per方法上。在

相关问题 更多 >