1 / 15

Python decorators

Useful Patterns & Idioms Trent Nelson ( tnelson@onresolve.com ). Python decorators. Overview. Initial experience learning decorators My own crude explanation/definition Some useful patterns/idioms. My Steps for Learning Decorators. Fired up Python Reference Manual

vinnie
Download Presentation

Python decorators

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Useful Patterns & Idioms Trent Nelson (tnelson@onresolve.com) Python decorators

  2. Overview • Initial experience learning decorators • My own crude explanation/definition • Some useful patterns/idioms

  3. My Steps for Learning Decorators • Fired up Python Reference Manual • Look up ‘decorators’ in index • No hits • Search for ‘decorators’ • Found PEP 318: Decorators for Functions and Methods • Nice bit of history • Doesn’t provide much in the way of education

  4. My Steps for Learning Decorators (cont.) • Stumbled upon ‘definition’ of decorators in section 7.6 of the Python Reference Manual: • “A function definition may be wrapped by one or more decorator expressions. Decorator expressions are evaluated when the function is defined, in the scope that contains the function definition. The result must be a callable, which is invoked with the function object as the only argument. The returned value is bound to the function name instead of the function object. Multiple decorators are applied in nested fashion.” • Well then...

  5. My Steps for Learning Decorators • Wouldn’t recommend this approach! • Surprisingly very little examples of how to actually write decorators in Python documentation • Had to google around to grok the concept • Would have preferred an explanation along the lines of...

  6. Decorators: My Crude Explanation by Example • Consider the following , which demonstrates two different types of decorators (one that doesn’t take any arguments, and one that does): class Foo(object):       @cache       def getExpensiveResource(self):            ...       @dll(c_char_p, returns=c_char_p)        def readSetting(self, setting):            ...   • First important point: code body of your decorator will differ depending on whether or not you accept arguments

  7. Decorator Without Arguments: @cache def cache(f):        # f: function object of decorated method; has        # useful info like f.func_name for the name of        # the decorated method.     def newf(*_args, **_kwds):            # This code will be executed in lieu of the            # method you've decorated.  You can call the           # decorated method via f(_args, _kwds).         ...            ...        return newf

  8. Decorator Without Arguments: @cache • Define your decorator to accept one parameter, ‘f’ • This will be the function object of the decorated method • Has useful info like f.func_name and f.f_frame • Define another method in the body, newf, that accepts the parameters *_args and **_kwds • Implement the body of your decorator in newf() • This will be called in lieu of the decorated method • Return newf at the end of your decorator def cache(f):        # f: function object of decorated method; has     # useful info like f.func_name for the name of     # the decorated method.     def newf(*_args, **_kwds):            # This code will be executed in lieu of the            # method you've decorated.  You can call the           # decorated method via f(_args, _kwds).         ...            ...        return newf

  9. Decorator With Arguments:@dll(c_char_p, returns=c_char_p) def dll(*args, **kwds):        # args[0]: c_char_p     # kwds['returns'] = c_char_p     def decorator(f):            # f: function object of decorated method; has            # useful info like f.func_name for the name of            # the decorated method.         def newf(*_args, **_kwds):                # This code will be executed in lieu of the                # method you've decorated.  You can call the                # decorated method via f(_args, _kwds).             ...                ...            return newf     return decorator

  10. Decorator With Arguments:@dll(c_char_p, returns=c_char_p) • Define your decorator as accepting two parameters, *args and **kwds • args[0]: c_char_p • kwds[‘returns’]: c_char_p • Define another method that takes a single parameter, ‘f’, which will be the function object of the decorated method • Define another method, newf, that accepts *_args, **_kwds • Implement the decorator body in newf • Return newf and decorator def dll(*args, **kwds):        # args[0]: c_char_p     # kwds['returns'] = c_char_p     def decorator(f):            # f: function object of decorated method; has            # useful info like f.func_name for the name of           # the decorated method.         def newf(*_args, **_kwds):                # This code will be executed in lieu of the             # method you've decorated.  You can call th             # decorated method via f(_args, _kwds).             ...                ...            return newf     return decorator

  11. Summary • If you don’t accept arguments: def cache(f): def newf(*_args, **kwds): ... return newf • If you do accept arguments: def dll(*args, **kwds): def decorator(f): def newf(*_args, **kwds): ... return newf return decorator • To call the original (decorated method) in newf(): result = f(_args, _kwds) • Next up: useful idioms

  12. Useful Idioms • @cache: caching results of expensive operations • @returns: casting return types to other objects • @dll: simplifying interface to a C DLL via ctypes • @db.execute, @db.select, @db.selectAll: going too far?

  13. Caching results of expensive operations: @cache • Definition: def cache(f):        def newf(*_args, **_kwds):            self = _args[0]    cacheName = '_cache_' + f.func_name         cache = self.__dict__.setdefault(cacheName, dict())            # Create a string representation of our decorated method's arguments to            # use as the cache key.  This ensures we only returned cached values for            # method invocations with identical arguments.            id = '%s,%s' % (repr(_args[1:]), repr(_kwds))            return cache.setdefault(id, f(*_args, **_kwds))        return newf • Sample usage: class Foo(object):       @cache       def expensiveOperation(foo, bar, *args, **kwds):            ...  

  14. @dll/@db • See demo.

  15. End of Presentation • Corresponding blog: • http://blogs.onresolve.com/?p=48 • Questions?

More Related