Clay Wardell
Clay Wardell

Reputation: 15602

Decorator that works on both classmethods and instance methods

I have two decorators, defined as follows, both of which do the exact same thing:

# 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

The reason I have two is because for class methods I need to pass in the first arg as cls=cls, and for instance methods I need to pass in self=self. But this is obviously not ideal. Does anyone know a way to structure a decorator that would work for instance methods and class methods?

Upvotes: 1

Views: 329

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1121484

Just pass in cls or self as the first positional argument, there is no need to pass them is as keyword arguments:

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

Upvotes: 3

Related Questions