适用于类方法和实例方法的装饰器
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
的第一个参数是关键字参数,self
或 cls
。这里真正需要调整的是没有为func的第一个参数使用关键字参数。
【参考方案1】:
只需传入cls
或self
作为第一个位置参数,不需要将它们作为关键字参数传递:
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
。以上是关于适用于类方法和实例方法的装饰器的主要内容,如果未能解决你的问题,请参考以下文章