A talk about the common problems about implementing your own decorators and the solutions in Python. Some examples on how decorators are used in the community and finally a few statistics about the use of them.
2.2 there was staticmethod, classmethod but no syntactic support for generic function transforms • Patching the function after the definition is suboptimal in readability • Syntactic brittleness • Structure information in simple and intuitive way • Delayed by syntax bikeshedding • Python 2.4 implemented PEP 318 on November 30, 2004 • PEP-3129 (class decorators) backported to 2.7 from 3.X
the Design Patterns by GoF • Comes from the notion of Decorated (or annotated) Parse Tree from compilers terminology: the process of evaluating attributes is called annotation, or DECORATION, of the parse tree
fib(n-2) if n > 2 else n >>> fib(10) 89 >>> fib(38) # ... long pause 63245986 %timeit fib(38) 4.83 s ± 17.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
citizen • are objects • call signature • Bound and unbound • Descriptor interface __get__ and __set__ • Use of functools.wraps • inspect.getargspec(fun)
if instance is None: if inspect.isclass(wrapped): # Decorator was applied to a class. return wrapped(*args, **kwargs) else: return wrapped(*args, **kwargs) # Decorator was applied to a function or staticmethod. else: if inspect.isclass(instance): return wrapped(*args, **kwargs) # Decorator was applied to a classmethod. else: return wrapped(*args, **kwargs) # Decorator applied to an instancemethod.
__init__(self, _check=False): self._data = {} def __getitem__(self, lookup): if isinstance(lookup, slice): return (self[index] for index in range(lookup.start or 0, lookup.stop, lookup.step or 1)) if lookup in {0, 1}: return lookup if self._data.get(lookup, None) is None: result = self[lookup-1] + self[lookup-2] self._data[lookup] = result return self._data[lookup] def on_methods(decorator): @wrapt.decorator def surrogate(target, instance, args, kwargs): items = target.__dict__.items() for name, attribute in items: if callable(attribute): setattr(target, name, decorator(attribute)) return target(*args, **kwargs) return surrogate
urllib2.urlopen('http://www.iana.org/domains/reserved').read() assert 'Example domains' in response • Run this test once, and VCR.py will record the HTTP request. • Run it again, and VCR.py will replay the response
3" # this will be equivalent to: class Compatible(object, metaclass=Meta): "In python3" class Compatible(object): "In python2" __metaclass__ = Meta @pytest.mark.xfail(raises=IOError) def test_fetch_feed(): "Verifies the retrieval of the feed object"
or profile code • Great for post-processing of results: i.e. json-serialize • Increase readability and signal intent • Don’t overuse them (more than 3 decorators) • Essential for deterministic testing • Can limit scope of monkey patching to functions