Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python functools.wraps equivalent for classes

When defining a decorator using a class, how do I automatically transfer over__name__, __module__ and __doc__? Normally, I would use the @wraps decorator from functools. Here's what I did instead for a class (this is not entirely my code):

class memoized:     """Decorator that caches a function's return value each time it is called.     If called later with the same arguments, the cached value is returned, and     not re-evaluated.     """     def __init__(self, func):         super().__init__()         self.func = func         self.cache = {}      def __call__(self, *args):         try:             return self.cache[args]         except KeyError:             value = self.func(*args)             self.cache[args] = value             return value         except TypeError:             # uncacheable -- for instance, passing a list as an argument.             # Better to not cache than to blow up entirely.             return self.func(*args)      def __repr__(self):         return self.func.__repr__()      def __get__(self, obj, objtype):         return functools.partial(self.__call__, obj)      __doc__ = property(lambda self:self.func.__doc__)     __module__ = property(lambda self:self.func.__module__)     __name__ = property(lambda self:self.func.__name__) 

Is there a standard decorator to automate the creation of name module and doc? Also, to automate the get method (I assume that's for creating bound methods?) Are there any missing methods?

like image 687
Neil G Avatar asked Jun 18 '11 07:06

Neil G


People also ask

How do you decorate a class in Python?

To decorate a method in a class, first use the '@' symbol followed by the name of the decorator function. A decorator is simply a function that takes a function as an argument and returns yet another function.

What does wraps do in Functools?

wraps() is a decorator that is applied to the wrapper function of a decorator. It updates the wrapper function to look like wrapped function by copying attributes such as __name__, __doc__ (the docstring), etc. Parameters: wrapped: The function name that is to be decorated by wrapper function.

Does Python have Functools?

The functools module, part of Python's standard Library, provides useful features that make it easier to work with high order functions (a function that returns a function or takes another function as an argument ).

What does Functools mean in Python?

Functools module is for higher-order functions that work on other functions. It provides functions for working with other functions and callable objects to use or extend them without completely rewriting them.


1 Answers

Everyone seems to have missed the obvious solution.

>>> import functools >>> class memoized(object):     """Decorator that caches a function's return value each time it is called.     If called later with the same arguments, the cached value is returned, and     not re-evaluated.     """     def __init__(self, func):         self.func = func         self.cache = {}         functools.update_wrapper(self, func)  ## TA-DA! ##     def __call__(self, *args):         pass  # Not needed for this demo.  >>> @memoized def fibonacci(n):     """fibonacci docstring"""     pass  # Not needed for this demo.  >>> fibonacci <__main__.memoized object at 0x0156DE30> >>> fibonacci.__name__ 'fibonacci' >>> fibonacci.__doc__ 'fibonacci docstring' 
like image 59
samwyse Avatar answered Sep 21 '22 05:09

samwyse