适用于类方法和实例方法的装饰器

Posted

技术标签:

【中文标题】适用于类方法和实例方法的装饰器【英文标题】:Decorator that works on both classmethods and instance methods 【发布时间】:2013-02-14 21:07:47 【问题描述】:

我有两个装饰器,定义如下,它们都做同样的事情:

# ONLY WORKS FOR CLASSMETHODS
def paginated_class_method(default_page_size=25):
    def wrap(func):
        @functools.wraps(func)
        def inner(cls, page=1, page_size=default_page_size, *args, **kwargs):
            objects = func(cls=cls, *args, **kwargs)
            return _paginate(objects, page, page_size)
        return inner
    return wrap


# ONLY WORKS FOR INSTANCEMETHODS
def paginated_instance_method(default_page_size=25):
    def wrap(func):
        @functools.wraps(func)
        def inner(self, page=1, page_size=default_page_size, *args, **kwargs):
            objects = func(self=self, *args, **kwargs)
            return _paginate(objects, page, page_size)
        return inner
    return wrap

我有两个的原因是因为对于类方法我需要将第一个 arg 传递为 cls=cls,而对于实例方法我需要传递 self=self。但这显然并不理想。有谁知道构造一个适用于实例方法和类方法的装饰器的方法?

【问题讨论】:

您根本不需要传入self cls 作为关键字参数。如果这些是位置,您可以使用任何本地名称。 @MartijnPieters 哦,我看到了问题;请注意,func 的第一个参数是关键字参数,selfcls。这里真正需要调整的是没有为func的第一个参数使用关键字参数。 【参考方案1】:

只需传入clsself 作为第一个位置参数,不需要将它们作为关键字参数传递:

def paginated_class_method(default_page_size=25):
    def wrap(func):
        @functools.wraps(func)
        def inner(self_or_cls, page=1, page_size=default_page_size, *args, **kwargs):
            objects = func(self_or_cls, *args, **kwargs)
            return _paginate(objects, page, page_size)
        return inner
    return wrap

【讨论】:

这是我尝试此策略时缺少的部分,我认为:args = [self_or_cls] + args 你不断以 2 秒的更新击败我的 cmets,从而使我的 cmets 变得无关紧要。 ;) @ClayWardell:你可以传入self_or_cls 作为第一个位置参数。 *args**kwargs 不排除使用其他位置参数。 @MartijnPieters 这很有效,非常感谢。我觉得我首先尝试过这样的事情,但我想我没有。如果我想在“裸”函数上使用它,而不是方法,我只需要在函数签名中包含 *args, **kwargs,对吧? @ClayWardell:没错。由于您无法真正检测到何时装饰方法与装饰函数(此时它们都是函数),您可能仍然需要支持两个版本。解决方法是始终只向装饰器添加关键字参数,并要求将它们称为作为关键字参数。然后你完全离开self_or_cls

以上是关于适用于类方法和实例方法的装饰器的主要内容,如果未能解决你的问题,请参考以下文章

蟒蛇 |实例化之前的类方法装饰器

在另一个类中使用实例方法作为装饰器

实例方法的装饰器可以访问该类吗?

Python functools.partial - 如何使用静态装饰器将其应用于类方法

使用类来写装饰器

在函数装饰器中调用 Python 实例方法