decorator-4.0.6/0000775000175000017500000000000012632446721014552 5ustar michelemichele00000000000000decorator-4.0.6/MANIFEST.in0000664000175000017500000000016212555631506016310 0ustar michelemichele00000000000000include docs/README.rst LICENSE.txt CHANGES.txt performance.sh documentation.pdf recursive-include src/tests *.py decorator-4.0.6/LICENSE.txt0000664000175000017500000000243512501550423016367 0ustar michelemichele00000000000000Copyright (c) 2005-2015, Michele Simionato All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in bytecode form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. decorator-4.0.6/PKG-INFO0000664000175000017500000000514312632446721015652 0ustar michelemichele00000000000000Metadata-Version: 1.1 Name: decorator Version: 4.0.6 Summary: Better living through Python with decorators Home-page: https://github.com/micheles/decorator Author: Michele Simionato Author-email: michele.simionato@gmail.com License: new BSD License Description: Decorator module ================= :Author: Michele Simionato :E-mail: michele.simionato@gmail.com :Requires: Python 2.6+ :Download page: http://pypi.python.org/pypi/decorator :Installation: ``pip install decorator`` :License: BSD license Installation ------------- If you are lazy, just perform `$ pip install decorator` which will install just the module on your system. If you prefer to install the full distribution from source, including the documentation, download the tarball_, unpack it and run `$ python setup.py install` in the main directory, possibly as superuser. .. _tarball: http://pypi.python.org/pypi/decorator Testing -------- Run `$ python src/tests/test.py -v` or (if you have setuptools installed) `$ python setup.py test` Notice that you may run into trouble if in your system there is an older version of the decorator module; in such a case remove the old version. It is safe even to copy the module `decorator.py` over an existing one, since version 4.0 is backward-compatible. Documentation -------------- There are various versions of the documentation: - `HTML version`_ - `PDF version`_ .. _HTML version: http://pythonhosted.org/decorator/documentation.html .. _PDF version: https://github.com/micheles/decorator/blob/4.0.4/documentation.pdf Repository --------------- The project is hosted on GitHub. You can look at the source here: https://github.com/micheles/decorator Keywords: decorators generic utility Platform: All Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: Utilities decorator-4.0.6/src/0000775000175000017500000000000012632446721015341 5ustar michelemichele00000000000000decorator-4.0.6/src/tests/0000775000175000017500000000000012632446721016503 5ustar michelemichele00000000000000decorator-4.0.6/src/tests/documentation.py0000664000175000017500000014551712632032307021732 0ustar michelemichele00000000000000from __future__ import print_function doc = r""" The ``decorator`` module ============================================================= :Author: Michele Simionato :E-mail: michele.simionato@gmail.com :Version: $VERSION ($DATE) :Supports: Python 2.6, 2.7, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5 :Download page: http://pypi.python.org/pypi/decorator/$VERSION :Installation: ``pip install decorator`` :License: BSD license .. contents:: Introduction ----------------------------------------- The decorator module is over ten years old, but still alive and kicking. It is used by several frameworks (IPython, scipy, authkit, pylons, pycuda, sugar, ...) and has been stable for a *long* time. It is your best option if you want to preserve the signature of decorated functions in a consistent way across Python releases. Version 4.0 is fully compatible with the past, except for one thing: support for Python 2.4 and 2.5 has been dropped. That decision made it possible to use a single code base both for Python 2.X and Python 3.X. This is a *huge* bonus, since I could remove over 2,000 lines of duplicated documentation/doctests. Having to maintain separate docs for Python 2 and Python 3 effectively stopped any development on the module for several years. Moreover, it is now trivial to distribute the module as an universal wheel_ since 2to3 is no more required. Since Python 2.5 has been released 9 years ago, I felt that it was reasonable to drop the support for it. If you need to support ancient versions of Python, stick with the decorator module version 3.4.2. This version supports all Python releases from 2.6 up to 3.5, which currently is still in beta status. .. _wheel: http://pythonwheels.com/ What's new --------------------- Since now there is a single manual for all Python versions, I took the occasion for overhauling the documentation. Therefore, even if you are an old time user, you may want to read the docs again, since several examples have been improved. The packaging has been improved and I am distributing the code in wheel format too. The integration with setuptools has been improved and now you can use ``python setup.py test`` to run the tests. A new utility function ``decorate(func, caller)`` has been added, doing the same job that in the past was done by ``decorator(caller, func)``. The old functionality is still there for compatibility sake, but it is deprecated and not documented anymore. Apart from that, there is a new experimental feature. The decorator module now includes an implementation of generic (multiple dispatch) functions. The API is designed to mimic the one of ``functools.singledispatch`` (introduced in Python 3.4) but the implementation is much simpler; moreover all the decorators involved preserve the signature of the decorated functions. For the moment the facility is there mostly to exemplify the power of the module. In the future it could be enhanced/optimized; on the other hand, both its behavior and its API could change. Such is the fate of experimental features. In any case it is very short and compact (less then one hundred lines) so you can extract it for your own use. Take it as food for thought. Usefulness of decorators ------------------------------------------------ Python decorators are an interesting example of why syntactic sugar matters. In principle, their introduction in Python 2.4 changed nothing, since they do not provide any new functionality which was not already present in the language. In practice, their introduction has significantly changed the way we structure our programs in Python. I believe the change is for the best, and that decorators are a great idea since: * decorators help reducing boilerplate code; * decorators help separation of concerns; * decorators enhance readability and maintenability; * decorators are explicit. Still, as of now, writing custom decorators correctly requires some experience and it is not as easy as it could be. For instance, typical implementations of decorators involve nested functions, and we all know that flat is better than nested. The aim of the ``decorator`` module it to simplify the usage of decorators for the average programmer, and to popularize decorators by showing various non-trivial examples. Of course, as all techniques, decorators can be abused (I have seen that) and you should not try to solve every problem with a decorator, just because you can. You may find the source code for all the examples discussed here in the ``documentation.py`` file, which contains the documentation you are reading in the form of doctests. Definitions ------------------------------------ Technically speaking, any Python object which can be called with one argument can be used as a decorator. However, this definition is somewhat too large to be really useful. It is more convenient to split the generic class of decorators in two subclasses: + *signature-preserving* decorators, i.e. callable objects taking a function as input and returning a function *with the same signature* as output; + *signature-changing* decorators, i.e. decorators that change the signature of their input function, or decorators returning non-callable objects. Signature-changing decorators have their use: for instance the builtin classes ``staticmethod`` and ``classmethod`` are in this group, since they take functions and return descriptor objects which are not functions, nor callables. However, signature-preserving decorators are more common and easier to reason about; in particular signature-preserving decorators can be composed together whereas other decorators in general cannot. Writing signature-preserving decorators from scratch is not that obvious, especially if one wants to define proper decorators that can accept functions with any signature. A simple example will clarify the issue. Statement of the problem ------------------------------ A very common use case for decorators is the memoization of functions. A ``memoize`` decorator works by caching the result of the function call in a dictionary, so that the next time the function is called with the same input parameters the result is retrieved from the cache and not recomputed. There are many implementations of ``memoize`` in http://www.python.org/moin/PythonDecoratorLibrary, but they do not preserve the signature. In recent versions of Python you can find a sophisticated ``lru_cache`` decorator in the standard library (in ``functools``). Here I am just interested in giving an example. A simple implementation could be the following (notice that in general it is impossible to memoize correctly something that depends on non-hashable arguments): $$memoize_uw Here I used the functools.update_wrapper_ utility, which has been added in Python 2.5 expressly to simplify the definition of decorators (in older versions of Python you need to copy the function attributes ``__name__``, ``__doc__``, ``__module__`` and ``__dict__`` from the original function to the decorated function by hand). Here is an example of usage: $$f1 .. _functools.update_wrapper: https://docs.python.org/3/library/functools.html#functools.update_wrapper The implementation above works in the sense that the decorator can accept functions with generic signatures; unfortunately this implementation does *not* define a signature-preserving decorator, since in general ``memoize_uw`` returns a function with a *different signature* from the original function. Consider for instance the following case: $$f1 Here the original function takes a single argument named ``x``, but the decorated function takes any number of arguments and keyword arguments: .. code-block:: python >>> from decorator import getargspec # akin to inspect.getargspec >>> print(getargspec(f1)) ArgSpec(args=[], varargs='args', varkw='kw', defaults=None) This means that introspection tools such as ``pydoc`` will give wrong informations about the signature of ``f1``, unless you are using Python 3.5. This is pretty bad: ``pydoc`` will tell you that the function accepts a generic signature ``*args``, ``**kw``, but when you try to call the function with more than an argument, you will get an error: .. code-block:: python >>> f1(0, 1) # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... TypeError: f1() takes exactly 1 positional argument (2 given) Notice even in Python 3.5 ``inspect.getargspec`` and ``inspect.getfullargspec`` (which are deprecated in that release) will give the wrong signature. The solution ----------------------------------------- The solution is to provide a generic factory of generators, which hides the complexity of making signature-preserving decorators from the application programmer. The ``decorate`` function in the ``decorator`` module is such a factory: .. code-block:: python >>> from decorator import decorate ``decorate`` takes two arguments, a caller function describing the functionality of the decorator and a function to be decorated; it returns the decorated function. The caller function must have signature ``(f, *args, **kw)`` and it must call the original function ``f`` with arguments ``args`` and ``kw``, implementing the wanted capability, i.e. memoization in this case: $$_memoize At this point you can define your decorator as follows: $$memoize The difference with respect to the ``memoize_uw`` approach, which is based on nested functions, is that the decorator module forces you to lift the inner function at the outer level. Moreover, you are forced to pass explicitly the function you want to decorate, there are no closures. Here is a test of usage: .. code-block:: python >>> @memoize ... def heavy_computation(): ... time.sleep(2) ... return "done" >>> print(heavy_computation()) # the first time it will take 2 seconds done >>> print(heavy_computation()) # the second time it will be instantaneous done The signature of ``heavy_computation`` is the one you would expect: .. code-block:: python >>> print(getargspec(heavy_computation)) ArgSpec(args=[], varargs=None, varkw=None, defaults=None) A ``trace`` decorator ------------------------------------------------------ As an additional example, here is how you can define a trivial ``trace`` decorator, which prints a message everytime the traced function is called: $$_trace $$trace Here is an example of usage: .. code-block:: python >>> @trace ... def f1(x): ... pass It is immediate to verify that ``f1`` works .. code-block:: python >>> f1(0) calling f1 with args (0,), {} and it that it has the correct signature: .. code-block:: python >>> print(getargspec(f1)) ArgSpec(args=['x'], varargs=None, varkw=None, defaults=None) The same decorator works with functions of any signature: .. code-block:: python >>> @trace ... def f(x, y=1, z=2, *args, **kw): ... pass >>> f(0, 3) calling f with args (0, 3, 2), {} >>> print(getargspec(f)) ArgSpec(args=['x', 'y', 'z'], varargs='args', varkw='kw', defaults=(1, 2)) $FUNCTION_ANNOTATIONS ``decorator.decorator`` --------------------------------------------- It may be annoying to write a caller function (like the ``_trace`` function above) and then a trivial wrapper (``def trace(f): return decorate(f, _trace)``) every time. For this reason, the ``decorator`` module provides an easy shortcut to convert the caller function into a signature-preserving decorator: the ``decorator`` function: .. code-block:: python >>> from decorator import decorator >>> print(decorator.__doc__) decorator(caller) converts a caller function into a decorator The ``decorator`` function can be used as a signature-changing decorator, just as ``classmethod`` and ``staticmethod``. However, ``classmethod`` and ``staticmethod`` return generic objects which are not callable, while ``decorator`` returns signature-preserving decorators, i.e. functions of a single argument. For instance, you can write directly .. code-block:: python >>> @decorator ... def trace(f, *args, **kw): ... kwstr = ', '.join('%r: %r' % (k, kw[k]) for k in sorted(kw)) ... print("calling %s with args %s, {%s}" % (f.__name__, args, kwstr)) ... return f(*args, **kw) and now ``trace`` will be a decorator. .. code-block:: python >>> trace # doctest: +ELLIPSIS Here is an example of usage: .. code-block:: python >>> @trace ... def func(): pass >>> func() calling func with args (), {} ``blocking`` ------------------------------------------- Sometimes one has to deal with blocking resources, such as ``stdin``, and sometimes it is best to have back a "busy" message than to block everything. This behavior can be implemented with a suitable family of decorators, where the parameter is the busy message: $$blocking Functions decorated with ``blocking`` will return a busy message if the resource is unavailable, and the intended result if the resource is available. For instance: .. code-block:: python >>> @blocking("Please wait ...") ... def read_data(): ... time.sleep(3) # simulate a blocking resource ... return "some data" >>> print(read_data()) # data is not available yet Please wait ... >>> time.sleep(1) >>> print(read_data()) # data is not available yet Please wait ... >>> time.sleep(1) >>> print(read_data()) # data is not available yet Please wait ... >>> time.sleep(1.1) # after 3.1 seconds, data is available >>> print(read_data()) some data ``decorator(cls)`` -------------------------------------------- The ``decorator`` facility can also produce a decorator starting from a class with the signature of a caller. In such a case the produced generator is able to convert functions into factories of instances of that class. As an example, here will I show a decorator which is able to convert a blocking function into an asynchronous function. The function, when called, is executed in a separate thread. This is very similar to the approach used in the ``concurrent.futures`` package. Of course the code here is just an example, it is not a recommended way of implementing futures. The implementation is the following: $$Future The decorated function returns a ``Future`` object, which has a ``.result()`` method which blocks until the underlying thread finishes and returns the final result. Here is a minimalistic example of usage: .. code-block:: python >>> futurefactory = decorator(Future) >>> @futurefactory ... def long_running(x): ... time.sleep(.5) ... return x >>> fut1 = long_running(1) >>> fut2 = long_running(2) >>> fut1.result() + fut2.result() 3 contextmanager ------------------------------------- For a long time Python had in its standard library a ``contextmanager`` decorator, able to convert generator functions into ``GeneratorContextManager`` factories. For instance if you write .. code-block:: python >>> from contextlib import contextmanager >>> @contextmanager ... def before_after(before, after): ... print(before) ... yield ... print(after) then ``before_after`` is a factory function returning ``GeneratorContextManager`` objects which can be used with the ``with`` statement: .. code-block:: python >>> with before_after('BEFORE', 'AFTER'): ... print('hello') BEFORE hello AFTER Basically, it is as if the content of the ``with`` block was executed in the place of the ``yield`` expression in the generator function. In Python 3.2 ``GeneratorContextManager`` objects were enhanced with a ``__call__`` method, so that they can be used as decorators as in this example: .. code-block:: python >>> @ba # doctest: +SKIP ... def hello(): ... print('hello') ... >>> hello() # doctest: +SKIP BEFORE hello AFTER The ``ba`` decorator is basically inserting a ``with ba:`` block inside the function. However there two issues: the first is that ``GeneratorContextManager`` objects are callable only in Python 3.2, so the previous example will break in older versions of Python (you can solve this by installing ``contextlib2``); the second is that ``GeneratorContextManager`` objects do not preserve the signature of the decorated functions: the decorated ``hello`` function here will have a generic signature ``hello(*args, **kwargs)`` but will break when called with more than zero arguments. For such reasons the decorator module, starting with release 3.4, offers a ``decorator.contextmanager`` decorator that solves both problems and works in all supported Python versions. The usage is the same and factories decorated with ``decorator.contextmanager`` will returns instances of ``ContextManager``, a subclass of ``contextlib.GeneratorContextManager`` with a ``__call__`` method acting as a signature-preserving decorator. The ``FunctionMaker`` class --------------------------------------------------------------- You may wonder about how the functionality of the ``decorator`` module is implemented. The basic building block is a ``FunctionMaker`` class which is able to generate on the fly functions with a given name and signature from a function template passed as a string. Generally speaking, you should not need to resort to ``FunctionMaker`` when writing ordinary decorators, but it is handy in some circumstances. You will see an example shortly, in the implementation of a cool decorator utility (``decorator_apply``). ``FunctionMaker`` provides a ``.create`` classmethod which takes as input the name, signature, and body of the function we want to generate as well as the execution environment where the function is generated by ``exec``. Here is an example: .. code-block:: python >>> def f(*args, **kw): # a function with a generic signature ... print(args, kw) >>> f1 = FunctionMaker.create('f1(a, b)', 'f(a, b)', dict(f=f)) >>> f1(1,2) (1, 2) {} It is important to notice that the function body is interpolated before being executed, so be careful with the ``%`` sign! ``FunctionMaker.create`` also accepts keyword arguments and such arguments are attached to the resulting function. This is useful if you want to set some function attributes, for instance the docstring ``__doc__``. For debugging/introspection purposes it may be useful to see the source code of the generated function; to do that, just pass the flag ``addsource=True`` and a ``__source__`` attribute will be added to the generated function: .. code-block:: python >>> f1 = FunctionMaker.create( ... 'f1(a, b)', 'f(a, b)', dict(f=f), addsource=True) >>> print(f1.__source__) def f1(a, b): f(a, b) ``FunctionMaker.create`` can take as first argument a string, as in the examples before, or a function. This is the most common usage, since typically you want to decorate a pre-existing function. A framework author may want to use directly ``FunctionMaker.create`` instead of ``decorator``, since it gives you direct access to the body of the generated function. For instance, suppose you want to instrument the ``__init__`` methods of a set of classes, by preserving their signature (such use case is not made up; this is done in SQAlchemy and in other frameworks). When the first argument of ``FunctionMaker.create`` is a function, a ``FunctionMaker`` object is instantiated internally, with attributes ``args``, ``varargs``, ``keywords`` and ``defaults`` which are the the return values of the standard library function ``inspect.getargspec``. For each argument in the ``args`` (which is a list of strings containing the names of the mandatory arguments) an attribute ``arg0``, ``arg1``, ..., ``argN`` is also generated. Finally, there is a ``signature`` attribute, a string with the signature of the original function. Notice: you should not pass signature strings with default arguments, i.e. something like ``'f1(a, b=None)'``. Just pass ``'f1(a, b)'`` and then a tuple of defaults: .. code-block:: python >>> f1 = FunctionMaker.create( ... 'f1(a, b)', 'f(a, b)', dict(f=f), addsource=True, defaults=(None,)) >>> print(getargspec(f1)) ArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=(None,)) Getting the source code --------------------------------------------------- Internally ``FunctionMaker.create`` uses ``exec`` to generate the decorated function. Therefore ``inspect.getsource`` will not work for decorated functions. That means that the usual ``??`` trick in IPython will give you the (right on the spot) message ``Dynamically generated function. No source code available``. In the past I have considered this acceptable, since ``inspect.getsource`` does not really work even with regular decorators. In that case ``inspect.getsource`` gives you the wrapper source code which is probably not what you want: $$identity_dec $$example .. code-block:: python >>> import inspect >>> print(inspect.getsource(example)) def wrapper(*args, **kw): return func(*args, **kw) (see bug report 1764286_ for an explanation of what is happening). Unfortunately the bug is still there, in all versions of Python except Python 3.5, which is not yet released. There is however a workaround. The decorated function has an attribute ``__wrapped__``, pointing to the original function. The easy way to get the source code is to call ``inspect.getsource`` on the undecorated function: .. code-block:: python >>> print(inspect.getsource(factorial.__wrapped__)) @tail_recursive def factorial(n, acc=1): "The good old factorial" if n == 0: return acc return factorial(n-1, n*acc) .. _1764286: http://bugs.python.org/issue1764286 Dealing with third party decorators ----------------------------------------------------------------- Sometimes you find on the net some cool decorator that you would like to include in your code. However, more often than not the cool decorator is not signature-preserving. Therefore you may want an easy way to upgrade third party decorators to signature-preserving decorators without having to rewrite them in terms of ``decorator``. You can use a ``FunctionMaker`` to implement that functionality as follows: $$decorator_apply ``decorator_apply`` sets the attribute ``__wrapped__`` of the generated function to the original function, so that you can get the right source code. If you are using a Python more recent than 3.2, you should also set the ``__qualname__`` attribute to preserve the qualified name of the original function. Notice that I am not providing this functionality in the ``decorator`` module directly since I think it is best to rewrite the decorator rather than adding an additional level of indirection. However, practicality beats purity, so you can add ``decorator_apply`` to your toolbox and use it if you need to. In order to give an example of usage of ``decorator_apply``, I will show a pretty slick decorator that converts a tail-recursive function in an iterative function. I have shamelessly stolen the basic idea from Kay Schluehr's recipe in the Python Cookbook, http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496691. $$TailRecursive Here the decorator is implemented as a class returning callable objects. $$tail_recursive Here is how you apply the upgraded decorator to the good old factorial: $$factorial .. code-block:: python >>> print(factorial(4)) 24 This decorator is pretty impressive, and should give you some food for your mind ;) Notice that there is no recursion limit now, and you can easily compute ``factorial(1001)`` or larger without filling the stack frame. Notice also that the decorator will not work on functions which are not tail recursive, such as the following $$fact (reminder: a function is tail recursive if it either returns a value without making a recursive call, or returns directly the result of a recursive call). Multiple dispatch ------------------------------------------- There has been talk of implementing multiple dispatch (i.e. generic) functions in Python for over ten years. Last year for the first time something concrete was done and now in Python 3.4 we have a decorator ``functools.singledispatch`` which can be used to implement generic functions. As the name implies, it has the restriction of being limited to single dispatch, i.e. it is able to dispatch on the first argument of the function only. The decorator module provide a decorator factory ``dispatch_on`` which can be used to implement generic functions dispatching on any argument; moreover it can manage dispatching on more than one argument and, of course, it is signature-preserving. Here I will give a very concrete example (taken from a real-life use case) where it is desiderable to dispatch on the second argument. Suppose you have an XMLWriter class, which is instantiated with some configuration parameters and has a ``.write`` method which is able to serialize objects to XML: $$XMLWriter Here you want to dispatch on the second argument since the first, ``self`` is already taken. The ``dispatch_on`` decorator factory allows you to specify the dispatch argument by simply passing its name as a string (notice that if you mispell the name you will get an error). The function decorated is turned into a generic function and it is the one which is called if there are no more specialized implementations. Usually such default function should raise a ``NotImplementedError``, thus forcing people to register some implementation. The registration can be done with a decorator: $$writefloat Now the XMLWriter is able to serialize floats: .. code-block:: python >>> writer = XMLWriter() >>> writer.write(2.3) '2.3' I could give a down-to-earth example of situations in which it is desiderable to dispatch on more than one argument (for instance once I implemented a database-access library where the first dispatching argument was the the database driver and the second one was the database record), but here I prefer to follow the tradition and show the time-honored Rock-Paper-Scissors example: $$Rock $$Paper $$Scissors I have added an ordinal to the Rock-Paper-Scissors classes to simplify the implementation. The idea is to define a generic function ``win(a, b)`` of two arguments corresponding to the moves of the first and second player respectively. The moves are instances of the classes Rock, Paper and Scissors; Paper wins over Rock, Scissors wins over Paper and Rock wins over Scissors. The function will return +1 for a win, -1 for a loss and 0 for parity. There are 9 combinations, however combinations with the same ordinal (i.e. the same class) return 0; moreover by exchanging the order of the arguments the sign of the result changes, so it is enough to specify directly only 3 implementations: $$win $$winRockPaper $$winPaperScissors $$winRockScissors Here is the result: .. code-block:: python >>> win(Paper(), Rock()) 1 >>> win(Scissors(), Paper()) 1 >>> win(Rock(), Scissors()) 1 >>> win(Paper(), Paper()) 0 >>> win(Rock(), Rock()) 0 >>> win(Scissors(), Scissors()) 0 >>> win(Rock(), Paper()) -1 >>> win(Paper(), Scissors()) -1 >>> win(Scissors(), Rock()) -1 The point of generic functions is that they play well with subclassing. For instance, suppose we define a StrongRock which does not lose against Paper: $$StrongRock $$winStrongRockPaper Then we do not need to define other implementations, since they are inherited from the parent: .. code-block:: python >>> win(StrongRock(), Scissors()) 1 You can introspect the precedence used by the dispath algorithm by calling ``.dispatch_info(*types)``: .. code-block:: python >>> win.dispatch_info(StrongRock, Scissors) [('StrongRock', 'Scissors'), ('Rock', 'Scissors')] Since there is no direct implementation for (StrongRock, Scissors) the dispatcher will look at the implementation for (Rock, Scissors) which is available. Internally the algorithm is doing a cross product of the class precedence lists (or Method Resolution Orders, MRO_ for short) of StrongRock and Scissors respectively. .. _MRO: http://www.python.org/2.3/mro.html Generic functions and virtual ancestors ------------------------------------------------- Generic function implementations in Python are complicated by the existence of "virtual ancestors", i.e. superclasses which are not in the class hierarchy. Consider for instance this class: $$WithLength This class defines a ``__len__`` method and as such is considered to be a subclass of the abstract base class ``collections.Sized``: .. code-block:: python >>> issubclass(WithLength, collections.Sized) True However, ``collections.Sized`` is not in the MRO_ of ``WithLength``, it is not a true ancestor. Any implementation of generic functions, even with single dispatch, must go through some contorsion to take into account the virtual ancestors. In particular if we define a generic function $$get_length implemented on all classes with a length $$get_length_sized then ``get_length`` must be defined on ``WithLength`` instances .. code-block:: python >>> get_length(WithLength()) 0 even if ``collections.Sized`` is not a true ancestor of ``WithLength``. Of course this is a contrived example since you could just use the builtin ``len``, but you should get the idea. Since in Python it is possible to consider any instance of ABCMeta as a virtual ancestor of any other class (it is enough to register it as ``ancestor.register(cls)``), any implementation of generic functions must take virtual ancestors into account. Let me give an example. Suppose you are using a third party set-like class like the following: $$SomeSet Here the author of ``SomeSet`` made a mistake by not inheriting from ``collections.Set``, but only from ``collections.Sized``. This is not a problem since you can register *a posteriori* ``collections.Set`` as a virtual ancestor of ``SomeSet``: .. code-block:: python >>> _ = collections.Set.register(SomeSet) >>> issubclass(SomeSet, collections.Set) True Now, let us define an implementation of ``get_length`` specific to set: $$get_length_set The current implementation, as the one used by ``functools.singledispatch``, is able to discern that a ``Set`` is a ``Sized`` object, so the more specific implementation for ``Set`` is taken: .. code-block:: python >>> get_length(SomeSet()) # NB: the implementation for Sized would give 0 1 Sometimes it is not clear how to dispatch. For instance, consider a class ``C`` registered both as ``collections.Iterable`` and ``collections.Sized`` and define a generic function ``g`` with implementations both for ``collections.Iterable`` and ``collections.Sized``. It is impossible to decide which implementation to use, since the ancestors are independent, and the following function will raise a RuntimeError when called: $$singledispatch_example1 This is consistent with the "refuse the temptation to guess" philosophy. ``functools.singledispatch`` would raise a similar error. It would be easy to rely on the order of registration to decide the precedence order. This is reasonable, but also fragile: if during some refactoring you change the registration order by mistake, a different implementation could be taken. If implementations of the generic functions are distributed across modules, and you change the import order, a different implementation could be taken. So the decorator module prefers to raise an error in the face of ambiguity. This is the same approach taken by the standard library. However, it should be noticed that the dispatch algorithm used by the decorator module is different from the one used by the standard library, so there are cases where you will get different answers. The difference is that ``functools.singledispatch`` tries to insert the virtual ancestors *before* the base classes, whereas ``decorator.dispatch_on`` tries to insert them *after* the base classes. I will give an example showing the difference: $$singledispatch_example2 If you play with this example and replace the ``singledispatch`` definition with ``functools.singledispatch``, the assert will break: ``g`` will return ``"container"`` instead of ``"s"``, because ``functools.singledispatch`` will insert the ``Container`` class right before ``S``. The only way to understand what is happening here is to scratch your head by looking at the implementations. I will just notice that ``.dispatch_info`` is quite useful: .. code-block:: python >>> g, V = singledispatch_example2() >>> g.dispatch_info(V) [('V',), ('Sized',), ('S',), ('Container',)] The current implementation does not implement any kind of cooperation between implementations, i.e. there is nothing akin to call-next-method in Lisp, nor akin to ``super`` in Python. Finally, let me notice that the decorator module implementation does not use any cache, whereas the one in ``singledispatch`` has a cache. Caveats and limitations ------------------------------------------- One thing you should be aware of, is the performance penalty of decorators. The worse case is shown by the following example:: $ cat performance.sh python3 -m timeit -s " from decorator import decorator @decorator def do_nothing(func, *args, **kw): return func(*args, **kw) @do_nothing def f(): pass " "f()" python3 -m timeit -s " def f(): pass " "f()" On my laptop, using the ``do_nothing`` decorator instead of the plain function is five times slower:: $ bash performance.sh 1000000 loops, best of 3: 1.39 usec per loop 1000000 loops, best of 3: 0.278 usec per loop It should be noted that a real life function would probably do something more useful than ``f`` here, and therefore in real life the performance penalty could be completely negligible. As always, the only way to know if there is a penalty in your specific use case is to measure it. More importantly, you should be aware that decorators will make your tracebacks longer and more difficult to understand. Consider this example: .. code-block:: python >>> @trace ... def f(): ... 1/0 Calling ``f()`` will give you a ``ZeroDivisionError``, but since the function is decorated the traceback will be longer: .. code-block:: python >>> f() # doctest: +ELLIPSIS Traceback (most recent call last): ... File "", line 2, in f File "", line 4, in trace return f(*args, **kw) File "", line 3, in f 1/0 ZeroDivisionError: ... You see here the inner call to the decorator ``trace``, which calls ``f(*args, **kw)``, and a reference to ``File "", line 2, in f``. This latter reference is due to the fact that internally the decorator module uses ``exec`` to generate the decorated function. Notice that ``exec`` is *not* responsibile for the performance penalty, since is the called *only once* at function decoration time, and not every time the decorated function is called. At present, there is no clean way to avoid ``exec``. A clean solution would require to change the CPython implementation of functions and add an hook to make it possible to change their signature directly. However, at present, even in Python 3.5 it is impossible to change the function signature directly, therefore the ``decorator`` module is still useful. Actually, this is the main reasons why I keep maintaining the module and releasing new versions. It should be noticed that in Python 3.5 a lot of improvements have been made: in that version you can decorated a function with ``func_tools.update_wrapper`` and ``pydoc`` will see the correct signature; still internally the function will have an incorrect signature, as you can see by using ``inspect.getfullargspec``: all documentation tools using such function (which has been correctly deprecated) will see the wrong signature. .. _362: http://www.python.org/dev/peps/pep-0362 In the present implementation, decorators generated by ``decorator`` can only be used on user-defined Python functions or methods, not on generic callable objects, nor on built-in functions, due to limitations of the ``inspect`` module in the standard library, especially for Python 2.X (in Python 3.5 a lot of such limitations have been removed). There is a strange quirk when decorating functions that take keyword arguments, if one of such arguments has the same name used in the caller function for the first argument. The quirk was reported by David Goldstein and here is an example where it is manifest: .. code-block:: python >>> @memoize ... def getkeys(**kw): ... return kw.keys() >>> getkeys(func='a') # doctest: +ELLIPSIS Traceback (most recent call last): ... TypeError: _memoize() got multiple values for ... 'func' The error message looks really strange until you realize that the caller function `_memoize` uses `func` as first argument, so there is a confusion between the positional argument and the keywork arguments. The solution is to change the name of the first argument in `_memoize`, or to change the implementation as follows: .. code-block:: python def _memoize(*all_args, **kw): func = all_args[0] args = all_args[1:] if kw: # frozenset is used to ensure hashability key = args, frozenset(kw.items()) else: key = args cache = func.cache # attribute added by memoize if key not in cache: cache[key] = func(*args, **kw) return cache[key] We have avoided the need to name the first argument, so the problem simply disappears. This is a technique that you should keep in mind when writing decorators for functions with keyword arguments. On a similar tone, there is a restriction on the names of the arguments: for instance, if try to call an argument ``_call_`` or ``_func_`` you will get a ``NameError``: .. code-block:: python >>> @trace ... def f(_func_): print(f) ... Traceback (most recent call last): ... NameError: _func_ is overridden in def f(_func_): return _call_(_func_, _func_) Finally, the implementation is such that the decorated function makes a (shallow) copy of the original function dictionary: .. code-block:: python >>> def f(): pass # the original function >>> f.attr1 = "something" # setting an attribute >>> f.attr2 = "something else" # setting another attribute >>> traced_f = trace(f) # the decorated function >>> traced_f.attr1 'something' >>> traced_f.attr2 = "something different" # setting attr >>> f.attr2 # the original attribute did not change 'something else' .. _function annotations: http://www.python.org/dev/peps/pep-3107/ .. _docutils: http://docutils.sourceforge.net/ .. _pygments: http://pygments.org/ LICENSE --------------------------------------------- Copyright (c) 2005-2015, Michele Simionato All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in bytecode form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. If you use this software and you are happy with it, consider sending me a note, just to gratify my ego. On the other hand, if you use this software and you are unhappy with it, send me a patch! """ function_annotations = """Function annotations --------------------------------------------- Python 3 introduced the concept of `function annotations`_,i.e. the ability to annotate the signature of a function with additional information, stored in a dictionary named ``__annotations__``. The decorator module, starting from release 3.3, is able to understand and to preserve the annotations. Here is an example: .. code-block:: python >>> @trace ... def f(x: 'the first argument', y: 'default argument'=1, z=2, ... *args: 'varargs', **kw: 'kwargs'): ... pass In order to introspect functions with annotations, one needs the utility ``inspect.getfullargspec``, new in Python 3 (and deprecated in favor of ``inspect.signature`` in Python 3.5): .. code-block:: python >>> from inspect import getfullargspec >>> argspec = getfullargspec(f) >>> argspec.args ['x', 'y', 'z'] >>> argspec.varargs 'args' >>> argspec.varkw 'kw' >>> argspec.defaults (1, 2) >>> argspec.kwonlyargs [] >>> argspec.kwonlydefaults You can check that the ``__annotations__`` dictionary is preserved: .. code-block:: python >>> f.__annotations__ is f.__wrapped__.__annotations__ True Here ``f.__wrapped__`` is the original undecorated function. Such an attribute is added to be consistent with the way ``functools.update_wrapper`` work. Another attribute which is copied from the original function is ``__qualname__``, the qualified name. This is an attribute which is present starting from Python 3.3. """ import sys import threading import time import functools import itertools import collections import collections as c from decorator import (decorator, decorate, FunctionMaker, contextmanager, dispatch_on, __version__) if sys.version < '3': function_annotations = '' today = time.strftime('%Y-%m-%d') __doc__ = (doc.replace('$VERSION', __version__).replace('$DATE', today) .replace('$FUNCTION_ANNOTATIONS', function_annotations)) def decorator_apply(dec, func): """ Decorate a function by preserving the signature even if dec is not a signature-preserving decorator. """ return FunctionMaker.create( func, 'return decfunc(%(signature)s)', dict(decfunc=dec(func)), __wrapped__=func) def _trace(f, *args, **kw): kwstr = ', '.join('%r: %r' % (k, kw[k]) for k in sorted(kw)) print("calling %s with args %s, {%s}" % (f.__name__, args, kwstr)) return f(*args, **kw) def trace(f): return decorate(f, _trace) class Future(threading.Thread): """ A class converting blocking functions into asynchronous functions by using threads. """ def __init__(self, func, *args, **kw): try: counter = func.counter except AttributeError: # instantiate the counter at the first call counter = func.counter = itertools.count(1) name = '%s-%s' % (func.__name__, next(counter)) def func_wrapper(): self._result = func(*args, **kw) super(Future, self).__init__(target=func_wrapper, name=name) self.start() def result(self): self.join() return self._result def identity_dec(func): def wrapper(*args, **kw): return func(*args, **kw) return wrapper @identity_dec def example(): pass def memoize_uw(func): func.cache = {} def memoize(*args, **kw): if kw: # frozenset is used to ensure hashability key = args, frozenset(kw.items()) else: key = args if key not in func.cache: func.cache[key] = func(*args, **kw) return func.cache[key] return functools.update_wrapper(memoize, func) @memoize_uw def f1(x): "Simulate some long computation" time.sleep(1) return x def _memoize(func, *args, **kw): if kw: # frozenset is used to ensure hashability key = args, frozenset(kw.items()) else: key = args cache = func.cache # attribute added by memoize if key not in cache: cache[key] = func(*args, **kw) return cache[key] def memoize(f): """ A simple memoize implementation. It works by adding a .cache dictionary to the decorated function. The cache will grow indefinitely, so it is your responsability to clear it, if needed. """ f.cache = {} return decorate(f, _memoize) def blocking(not_avail): def _blocking(f, *args, **kw): if not hasattr(f, "thread"): # no thread running def set_result(): f.result = f(*args, **kw) f.thread = threading.Thread(None, set_result) f.thread.start() return not_avail elif f.thread.isAlive(): return not_avail else: # the thread is ended, return the stored result del f.thread return f.result return decorator(_blocking) class User(object): "Will just be able to see a page" class PowerUser(User): "Will be able to add new pages too" class Admin(PowerUser): "Will be able to delete pages too" def get_userclass(): return User class PermissionError(Exception): pass def restricted(user_class): def restricted(func, *args, **kw): "Restrict access to a given class of users" userclass = get_userclass() if issubclass(userclass, user_class): return func(*args, **kw) else: raise PermissionError( '%s does not have the permission to run %s!' % (userclass.__name__, func.__name__)) return decorator(restricted) class Action(object): """ >>> a = Action() >>> a.view() # ok >>> a.insert() # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... PermissionError: User does not have the permission to run insert! """ @restricted(User) def view(self): pass @restricted(PowerUser) def insert(self): pass @restricted(Admin) def delete(self): pass class TailRecursive(object): """ tail_recursive decorator based on Kay Schluehr's recipe http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496691 with improvements by me and George Sakkis. """ def __init__(self, func): self.func = func self.firstcall = True self.CONTINUE = object() # sentinel def __call__(self, *args, **kwd): CONTINUE = self.CONTINUE if self.firstcall: func = self.func self.firstcall = False try: while True: result = func(*args, **kwd) if result is CONTINUE: # update arguments args, kwd = self.argskwd else: # last call return result finally: self.firstcall = True else: # return the arguments of the tail call self.argskwd = args, kwd return CONTINUE def tail_recursive(func): return decorator_apply(TailRecursive, func) @tail_recursive def factorial(n, acc=1): "The good old factorial" if n == 0: return acc return factorial(n-1, n*acc) def fact(n): # this is not tail-recursive if n == 0: return 1 return n * fact(n-1) def a_test_for_pylons(): """ In version 3.1.0 decorator(caller) returned a nameless partial object, thus breaking Pylons. That must not happen again. >>> decorator(_memoize).__name__ '_memoize' Here is another bug of version 3.1.1 missing the docstring: >>> factorial.__doc__ 'The good old factorial' """ if sys.version >= '3': # tests for signatures specific to Python 3 def test_kwonlydefaults(): """ >>> @trace ... def f(arg, defarg=1, *args, kwonly=2): pass ... >>> f.__kwdefaults__ {'kwonly': 2} """ def test_kwonlyargs(): """ >>> @trace ... def func(a, b, *args, y=2, z=3, **kwargs): ... return y, z ... >>> func('a', 'b', 'c', 'd', 'e', y='y', z='z', cat='dog') calling func with args ('a', 'b', 'c', 'd', 'e'), {'cat': 'dog', 'y': 'y', 'z': 'z'} ('y', 'z') """ def test_kwonly_no_args(): """# this was broken with decorator 3.3.3 >>> @trace ... def f(**kw): pass ... >>> f() calling f with args (), {} """ def test_kwonly_star_notation(): """ >>> @trace ... def f(*, a=1, **kw): pass ... >>> import inspect >>> inspect.getfullargspec(f) FullArgSpec(args=[], varargs=None, varkw='kw', defaults=None, kwonlyargs=['a'], kwonlydefaults={'a': 1}, annotations={}) """ @contextmanager def before_after(before, after): print(before) yield print(after) ba = before_after('BEFORE', 'AFTER') # ContextManager instance @ba def hello(user): """ >>> ba.__class__.__name__ 'ContextManager' >>> hello('michele') BEFORE hello michele AFTER """ print('hello %s' % user) # ####################### multiple dispatch ############################ # class XMLWriter(object): def __init__(self, **config): self.cfg = config @dispatch_on('obj') def write(self, obj): raise NotImplementedError(type(obj)) @XMLWriter.write.register(float) def writefloat(self, obj): return '%s' % obj class Rock(object): ordinal = 0 class Paper(object): ordinal = 1 class Scissors(object): ordinal = 2 class StrongRock(Rock): pass @dispatch_on('a', 'b') def win(a, b): if a.ordinal == b.ordinal: return 0 elif a.ordinal > b.ordinal: return -win(b, a) raise NotImplementedError((type(a), type(b))) @win.register(Rock, Paper) def winRockPaper(a, b): return -1 @win.register(Rock, Scissors) def winRockScissors(a, b): return 1 @win.register(Paper, Scissors) def winPaperScissors(a, b): return -1 @win.register(StrongRock, Paper) def winStrongRockPaper(a, b): return 0 class WithLength(object): def __len__(self): return 0 class SomeSet(collections.Sized): # methods that make SomeSet set-like # not shown ... def __len__(self): return 0 @dispatch_on('obj') def get_length(obj): raise NotImplementedError(type(obj)) @get_length.register(collections.Sized) def get_length_sized(obj): return len(obj) @get_length.register(collections.Set) def get_length_set(obj): return 1 class C(object): "Registered as Sized and Iterable" collections.Sized.register(C) collections.Iterable.register(C) def singledispatch_example1(): singledispatch = dispatch_on('obj') @singledispatch def g(obj): raise NotImplementedError(type(g)) @g.register(collections.Sized) def g_sized(object): return "sized" @g.register(collections.Iterable) def g_iterable(object): return "iterable" g(C()) # RuntimeError: Ambiguous dispatch: Iterable or Sized? def singledispatch_example2(): # adapted from functools.singledispatch test case singledispatch = dispatch_on('arg') class S(object): pass class V(c.Sized, S): def __len__(self): return 0 @singledispatch def g(arg): return "base" @g.register(S) def g_s(arg): return "s" @g.register(c.Container) def g_container(arg): return "container" v = V() assert g(v) == "s" c.Container.register(V) # add c.Container to the virtual mro of V assert g(v) == "s" # since the virtual mro is V, Sized, S, Container return g, V if __name__ == '__main__': import doctest doctest.testmod() decorator-4.0.6/src/tests/__init__.py0000664000175000017500000000000012554406023020574 0ustar michelemichele00000000000000decorator-4.0.6/src/tests/test.py0000664000175000017500000002765312632032307020040 0ustar michelemichele00000000000000from __future__ import absolute_import import sys import doctest import unittest import decimal import inspect import functools import collections from decorator import dispatch_on, contextmanager, decorator try: from . import documentation as doc except (SystemError, ValueError): import documentation as doc @contextmanager def assertRaises(etype): """This works in Python 2.6 too""" try: yield except etype: pass else: raise Exception('Expected %s' % etype.__name__) class DocumentationTestCase(unittest.TestCase): def test(self): err = doctest.testmod(doc)[0] self.assertEqual(err, 0) def test_singledispatch1(self): if hasattr(functools, 'singledispatch'): with assertRaises(RuntimeError): doc.singledispatch_example1() def test_singledispatch2(self): if hasattr(functools, 'singledispatch'): doc.singledispatch_example2() class ExtraTestCase(unittest.TestCase): def test_qualname(self): if sys.version >= '3.3': self.assertEqual(doc.hello.__qualname__, 'hello') else: with assertRaises(AttributeError): doc.hello.__qualname__ def test_signature(self): if hasattr(inspect, 'signature'): sig = inspect.signature(doc.f1) self.assertEqual(str(sig), '(x)') def test_unique_filenames(self): @decorator def d1(f, *args, **kwargs): return f(*args, **kwargs) @decorator def d2(f, *args, **kwargs): return f(*args, **kwargs) @d1 def f1(x, y, z): pass @d2 def f2(x, y, z): pass f1_orig = f1 @d1 def f1(x, y, z): pass self.assertNotEqual(d1.__code__.co_filename, d2.__code__.co_filename) self.assertNotEqual(f1.__code__.co_filename, f2.__code__.co_filename) self.assertNotEqual(f1_orig.__code__.co_filename, f1.__code__.co_filename) def test_no_first_arg(self): @decorator def example(*args, **kw): return args[0](*args[1:], **kw) @example def func(**kw): return kw # there is no confusion when passing args as a keyword argument self.assertEqual(func(args='a'), {'args': 'a'}) # ################### test dispatch_on ############################# # # adapted from test_functools in Python 3.5 singledispatch = dispatch_on('obj') class TestSingleDispatch(unittest.TestCase): def test_simple_overloads(self): @singledispatch def g(obj): return "base" @g.register(int) def g_int(i): return "integer" self.assertEqual(g("str"), "base") self.assertEqual(g(1), "integer") self.assertEqual(g([1, 2, 3]), "base") def test_mro(self): @singledispatch def g(obj): return "base" class A(object): pass class C(A): pass class B(A): pass class D(C, B): pass @g.register(A) def g_A(a): return "A" @g.register(B) def g_B(b): return "B" self.assertEqual(g(A()), "A") self.assertEqual(g(B()), "B") self.assertEqual(g(C()), "A") self.assertEqual(g(D()), "B") def test_register_decorator(self): @singledispatch def g(obj): return "base" @g.register(int) def g_int(i): return "int %s" % (i,) self.assertEqual(g(""), "base") self.assertEqual(g(12), "int 12") def test_register_error(self): @singledispatch def g(obj): return "base" with assertRaises(TypeError): # wrong number of arguments @g.register(int) def g_int(): return "int" def test_wrapping_attributes(self): @singledispatch def g(obj): "Simple test" return "Test" self.assertEqual(g.__name__, "g") if sys.flags.optimize < 2: self.assertEqual(g.__doc__, "Simple test") def test_c_classes(self): @singledispatch def g(obj): return "base" @g.register(decimal.DecimalException) def _(obj): return obj.args subn = decimal.Subnormal("Exponent < Emin") rnd = decimal.Rounded("Number got rounded") self.assertEqual(g(subn), ("Exponent < Emin",)) self.assertEqual(g(rnd), ("Number got rounded",)) @g.register(decimal.Subnormal) def _g(obj): return "Too small to care." self.assertEqual(g(subn), "Too small to care.") self.assertEqual(g(rnd), ("Number got rounded",)) def test_register_abc(self): c = collections d = {"a": "b"} l = [1, 2, 3] s = set([object(), None]) f = frozenset(s) t = (1, 2, 3) @singledispatch def g(obj): return "base" self.assertEqual(g(d), "base") self.assertEqual(g(l), "base") self.assertEqual(g(s), "base") self.assertEqual(g(f), "base") self.assertEqual(g(t), "base") g.register(c.Sized)(lambda obj: "sized") self.assertEqual(g(d), "sized") self.assertEqual(g(l), "sized") self.assertEqual(g(s), "sized") self.assertEqual(g(f), "sized") self.assertEqual(g(t), "sized") g.register(c.MutableMapping)(lambda obj: "mutablemapping") self.assertEqual(g(d), "mutablemapping") self.assertEqual(g(l), "sized") self.assertEqual(g(s), "sized") self.assertEqual(g(f), "sized") self.assertEqual(g(t), "sized") if hasattr(c, 'ChainMap'): g.register(c.ChainMap)(lambda obj: "chainmap") # irrelevant ABCs registered self.assertEqual(g(d), "mutablemapping") self.assertEqual(g(l), "sized") self.assertEqual(g(s), "sized") self.assertEqual(g(f), "sized") self.assertEqual(g(t), "sized") g.register(c.MutableSequence)(lambda obj: "mutablesequence") self.assertEqual(g(d), "mutablemapping") self.assertEqual(g(l), "mutablesequence") self.assertEqual(g(s), "sized") self.assertEqual(g(f), "sized") self.assertEqual(g(t), "sized") g.register(c.MutableSet)(lambda obj: "mutableset") self.assertEqual(g(d), "mutablemapping") self.assertEqual(g(l), "mutablesequence") self.assertEqual(g(s), "mutableset") self.assertEqual(g(f), "sized") self.assertEqual(g(t), "sized") g.register(c.Mapping)(lambda obj: "mapping") self.assertEqual(g(d), "mutablemapping") # not specific enough self.assertEqual(g(l), "mutablesequence") self.assertEqual(g(s), "mutableset") self.assertEqual(g(f), "sized") self.assertEqual(g(t), "sized") g.register(c.Sequence)(lambda obj: "sequence") self.assertEqual(g(d), "mutablemapping") self.assertEqual(g(l), "mutablesequence") self.assertEqual(g(s), "mutableset") self.assertEqual(g(f), "sized") self.assertEqual(g(t), "sequence") g.register(c.Set)(lambda obj: "set") self.assertEqual(g(d), "mutablemapping") self.assertEqual(g(l), "mutablesequence") self.assertEqual(g(s), "mutableset") self.assertEqual(g(f), "set") self.assertEqual(g(t), "sequence") g.register(dict)(lambda obj: "dict") self.assertEqual(g(d), "dict") self.assertEqual(g(l), "mutablesequence") self.assertEqual(g(s), "mutableset") self.assertEqual(g(f), "set") self.assertEqual(g(t), "sequence") g.register(list)(lambda obj: "list") self.assertEqual(g(d), "dict") self.assertEqual(g(l), "list") self.assertEqual(g(s), "mutableset") self.assertEqual(g(f), "set") self.assertEqual(g(t), "sequence") g.register(set)(lambda obj: "concrete-set") self.assertEqual(g(d), "dict") self.assertEqual(g(l), "list") self.assertEqual(g(s), "concrete-set") self.assertEqual(g(f), "set") self.assertEqual(g(t), "sequence") g.register(frozenset)(lambda obj: "frozen-set") self.assertEqual(g(d), "dict") self.assertEqual(g(l), "list") self.assertEqual(g(s), "concrete-set") self.assertEqual(g(f), "frozen-set") self.assertEqual(g(t), "sequence") g.register(tuple)(lambda obj: "tuple") self.assertEqual(g(d), "dict") self.assertEqual(g(l), "list") self.assertEqual(g(s), "concrete-set") self.assertEqual(g(f), "frozen-set") self.assertEqual(g(t), "tuple") def test_mro_conflicts(self): c = collections @singledispatch def g(obj): return "base" class O(c.Sized): def __len__(self): return 0 o = O() self.assertEqual(g(o), "base") g.register(c.Iterable)(lambda arg: "iterable") g.register(c.Container)(lambda arg: "container") g.register(c.Sized)(lambda arg: "sized") g.register(c.Set)(lambda arg: "set") self.assertEqual(g(o), "sized") c.Iterable.register(O) self.assertEqual(g(o), "sized") c.Container.register(O) with assertRaises(RuntimeError): # was "sized" because in mro self.assertEqual(g(o), "sized") c.Set.register(O) self.assertEqual(g(o), "set") class P(object): pass p = P() self.assertEqual(g(p), "base") c.Iterable.register(P) self.assertEqual(g(p), "iterable") c.Container.register(P) with assertRaises(RuntimeError): self.assertEqual(g(p), "iterable") class Q(c.Sized): def __len__(self): return 0 q = Q() self.assertEqual(g(q), "sized") c.Iterable.register(Q) self.assertEqual(g(q), "sized") c.Set.register(Q) self.assertEqual(g(q), "set") # because c.Set is a subclass of c.Sized and c.Iterable @singledispatch def h(obj): return "base" @h.register(c.Sized) def h_sized(arg): return "sized" @h.register(c.Container) def h_container(arg): return "container" # Even though Sized and Container are explicit bases of MutableMapping, # this ABC is implicitly registered on defaultdict which makes all of # MutableMapping's bases implicit as well from defaultdict's # perspective. with assertRaises(RuntimeError): self.assertEqual(h(c.defaultdict(lambda: 0)), "sized") class R(c.defaultdict): pass c.MutableSequence.register(R) @singledispatch def i(obj): return "base" @i.register(c.MutableMapping) def i_mapping(arg): return "mapping" @i.register(c.MutableSequence) def i_sequence(arg): return "sequence" r = R() with assertRaises(RuntimeError): # was no error self.assertEqual(i(r), "sequence") class S(object): pass class T(S, c.Sized): def __len__(self): return 0 t = T() self.assertEqual(h(t), "sized") c.Container.register(T) self.assertEqual(h(t), "sized") # because it's explicitly in the MRO class U(object): def __len__(self): return 0 u = U() self.assertEqual(h(u), "sized") # implicit Sized subclass inferred # from the existence of __len__() c.Container.register(U) # There is no preference for registered versus inferred ABCs. with assertRaises(RuntimeError): h(u) if __name__ == '__main__': unittest.main() decorator-4.0.6/src/decorator.egg-info/0000775000175000017500000000000012632446721021015 5ustar michelemichele00000000000000decorator-4.0.6/src/decorator.egg-info/PKG-INFO0000664000175000017500000000514312632446712022115 0ustar michelemichele00000000000000Metadata-Version: 1.1 Name: decorator Version: 4.0.6 Summary: Better living through Python with decorators Home-page: https://github.com/micheles/decorator Author: Michele Simionato Author-email: michele.simionato@gmail.com License: new BSD License Description: Decorator module ================= :Author: Michele Simionato :E-mail: michele.simionato@gmail.com :Requires: Python 2.6+ :Download page: http://pypi.python.org/pypi/decorator :Installation: ``pip install decorator`` :License: BSD license Installation ------------- If you are lazy, just perform `$ pip install decorator` which will install just the module on your system. If you prefer to install the full distribution from source, including the documentation, download the tarball_, unpack it and run `$ python setup.py install` in the main directory, possibly as superuser. .. _tarball: http://pypi.python.org/pypi/decorator Testing -------- Run `$ python src/tests/test.py -v` or (if you have setuptools installed) `$ python setup.py test` Notice that you may run into trouble if in your system there is an older version of the decorator module; in such a case remove the old version. It is safe even to copy the module `decorator.py` over an existing one, since version 4.0 is backward-compatible. Documentation -------------- There are various versions of the documentation: - `HTML version`_ - `PDF version`_ .. _HTML version: http://pythonhosted.org/decorator/documentation.html .. _PDF version: https://github.com/micheles/decorator/blob/4.0.4/documentation.pdf Repository --------------- The project is hosted on GitHub. You can look at the source here: https://github.com/micheles/decorator Keywords: decorators generic utility Platform: All Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: Utilities decorator-4.0.6/src/decorator.egg-info/top_level.txt0000664000175000017500000000001212632446712023540 0ustar michelemichele00000000000000decorator decorator-4.0.6/src/decorator.egg-info/dependency_links.txt0000664000175000017500000000000112632446712025063 0ustar michelemichele00000000000000 decorator-4.0.6/src/decorator.egg-info/not-zip-safe0000664000175000017500000000000112601127420023227 0ustar michelemichele00000000000000 decorator-4.0.6/src/decorator.egg-info/SOURCES.txt0000664000175000017500000000056312632446712022705 0ustar michelemichele00000000000000CHANGES.txt LICENSE.txt MANIFEST.in documentation.pdf performance.sh setup.cfg setup.py docs/README.rst src/decorator.py src/decorator.egg-info/PKG-INFO src/decorator.egg-info/SOURCES.txt src/decorator.egg-info/dependency_links.txt src/decorator.egg-info/not-zip-safe src/decorator.egg-info/top_level.txt src/tests/__init__.py src/tests/documentation.py src/tests/test.pydecorator-4.0.6/src/decorator.py0000664000175000017500000003650212632446456017710 0ustar michelemichele00000000000000# ######################### LICENSE ############################ # # Copyright (c) 2005-2015, Michele Simionato # All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # Redistributions in bytecode form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. """ Decorator module, see http://pypi.python.org/pypi/decorator for the documentation. """ from __future__ import print_function import re import sys import inspect import operator import itertools import collections __version__ = '4.0.6' if sys.version >= '3': from inspect import getfullargspec def get_init(cls): return cls.__init__ else: class getfullargspec(object): "A quick and dirty replacement for getfullargspec for Python 2.X" def __init__(self, f): self.args, self.varargs, self.varkw, self.defaults = \ inspect.getargspec(f) self.kwonlyargs = [] self.kwonlydefaults = None def __iter__(self): yield self.args yield self.varargs yield self.varkw yield self.defaults getargspec = inspect.getargspec def get_init(cls): return cls.__init__.__func__ # getargspec has been deprecated in Python 3.5 ArgSpec = collections.namedtuple( 'ArgSpec', 'args varargs varkw defaults') def getargspec(f): """A replacement for inspect.getargspec""" spec = getfullargspec(f) return ArgSpec(spec.args, spec.varargs, spec.varkw, spec.defaults) DEF = re.compile('\s*def\s*([_\w][_\w\d]*)\s*\(') # basic functionality class FunctionMaker(object): """ An object with the ability to create functions with a given signature. It has attributes name, doc, module, signature, defaults, dict and methods update and make. """ # Atomic get-and-increment provided by the GIL _compile_count = itertools.count() def __init__(self, func=None, name=None, signature=None, defaults=None, doc=None, module=None, funcdict=None): self.shortsignature = signature if func: # func can be a class or a callable, but not an instance method self.name = func.__name__ if self.name == '': # small hack for lambda functions self.name = '_lambda_' self.doc = func.__doc__ self.module = func.__module__ if inspect.isfunction(func): argspec = getfullargspec(func) self.annotations = getattr(func, '__annotations__', {}) for a in ('args', 'varargs', 'varkw', 'defaults', 'kwonlyargs', 'kwonlydefaults'): setattr(self, a, getattr(argspec, a)) for i, arg in enumerate(self.args): setattr(self, 'arg%d' % i, arg) if sys.version < '3': # easy way self.shortsignature = self.signature = ( inspect.formatargspec( formatvalue=lambda val: "", *argspec)[1:-1]) else: # Python 3 way allargs = list(self.args) allshortargs = list(self.args) if self.varargs: allargs.append('*' + self.varargs) allshortargs.append('*' + self.varargs) elif self.kwonlyargs: allargs.append('*') # single star syntax for a in self.kwonlyargs: allargs.append('%s=None' % a) allshortargs.append('%s=%s' % (a, a)) if self.varkw: allargs.append('**' + self.varkw) allshortargs.append('**' + self.varkw) self.signature = ', '.join(allargs) self.shortsignature = ', '.join(allshortargs) self.dict = func.__dict__.copy() # func=None happens when decorating a caller if name: self.name = name if signature is not None: self.signature = signature if defaults: self.defaults = defaults if doc: self.doc = doc if module: self.module = module if funcdict: self.dict = funcdict # check existence required attributes assert hasattr(self, 'name') if not hasattr(self, 'signature'): raise TypeError('You are decorating a non function: %s' % func) def update(self, func, **kw): "Update the signature of func with the data in self" func.__name__ = self.name func.__doc__ = getattr(self, 'doc', None) func.__dict__ = getattr(self, 'dict', {}) func.__defaults__ = getattr(self, 'defaults', ()) func.__kwdefaults__ = getattr(self, 'kwonlydefaults', None) func.__annotations__ = getattr(self, 'annotations', None) try: frame = sys._getframe(3) except AttributeError: # for IronPython and similar implementations callermodule = '?' else: callermodule = frame.f_globals.get('__name__', '?') func.__module__ = getattr(self, 'module', callermodule) func.__dict__.update(kw) def make(self, src_templ, evaldict=None, addsource=False, **attrs): "Make a new function from a given template and update the signature" src = src_templ % vars(self) # expand name and signature evaldict = evaldict or {} mo = DEF.match(src) if mo is None: raise SyntaxError('not a valid function template\n%s' % src) name = mo.group(1) # extract the function name names = set([name] + [arg.strip(' *') for arg in self.shortsignature.split(',')]) for n in names: if n in ('_func_', '_call_'): raise NameError('%s is overridden in\n%s' % (n, src)) # Ensure each generated function has a unique filename for profilers # (such as cProfile) that depend on the tuple of (, # , ) being unique. filename = '' % (next(self._compile_count),) try: code = compile(src, filename, 'single') exec(code, evaldict) except: print('Error in generated code:', file=sys.stderr) print(src, file=sys.stderr) raise func = evaldict[name] if addsource: attrs['__source__'] = src self.update(func, **attrs) return func @classmethod def create(cls, obj, body, evaldict, defaults=None, doc=None, module=None, addsource=True, **attrs): """ Create a function from the strings name, signature and body. evaldict is the evaluation dictionary. If addsource is true an attribute __source__ is added to the result. The attributes attrs are added, if any. """ if isinstance(obj, str): # "name(signature)" name, rest = obj.strip().split('(', 1) signature = rest[:-1] # strip a right parens func = None else: # a function name = None signature = None func = obj self = cls(func, name, signature, defaults, doc, module) ibody = '\n'.join(' ' + line for line in body.splitlines()) return self.make('def %(name)s(%(signature)s):\n' + ibody, evaldict, addsource, **attrs) def decorate(func, caller): """ decorate(func, caller) decorates a function using a caller. """ evaldict = dict(_call_=caller, _func_=func) fun = FunctionMaker.create( func, "return _call_(_func_, %(shortsignature)s)", evaldict, __wrapped__=func) if hasattr(func, '__qualname__'): fun.__qualname__ = func.__qualname__ return fun def decorator(caller, _func=None): """decorator(caller) converts a caller function into a decorator""" if _func is not None: # return a decorated function # this is obsolete behavior; you should use decorate instead return decorate(_func, caller) # else return a decorator function if inspect.isclass(caller): name = caller.__name__.lower() doc = 'decorator(%s) converts functions/generators into ' \ 'factories of %s objects' % (caller.__name__, caller.__name__) elif inspect.isfunction(caller): if caller.__name__ == '': name = '_lambda_' else: name = caller.__name__ doc = caller.__doc__ else: # assume caller is an object with a __call__ method name = caller.__class__.__name__.lower() doc = caller.__call__.__doc__ evaldict = dict(_call_=caller, _decorate_=decorate) return FunctionMaker.create( '%s(func)' % name, 'return _decorate_(func, _call_)', evaldict, doc=doc, module=caller.__module__, __wrapped__=caller) # ####################### contextmanager ####################### # try: # Python >= 3.2 from contextlib import _GeneratorContextManager except ImportError: # Python >= 2.5 from contextlib import GeneratorContextManager as _GeneratorContextManager class ContextManager(_GeneratorContextManager): def __call__(self, func): """Context manager decorator""" return FunctionMaker.create( func, "with _self_: return _func_(%(shortsignature)s)", dict(_self_=self, _func_=func), __wrapped__=func) init = getfullargspec(_GeneratorContextManager.__init__) n_args = len(init.args) if n_args == 2 and not init.varargs: # (self, genobj) Python 2.7 def __init__(self, g, *a, **k): return _GeneratorContextManager.__init__(self, g(*a, **k)) ContextManager.__init__ = __init__ elif n_args == 2 and init.varargs: # (self, gen, *a, **k) Python 3.4 pass elif n_args == 4: # (self, gen, args, kwds) Python 3.5 def __init__(self, g, *a, **k): return _GeneratorContextManager.__init__(self, g, a, k) ContextManager.__init__ = __init__ contextmanager = decorator(ContextManager) # ############################ dispatch_on ############################ # def append(a, vancestors): """ Append ``a`` to the list of the virtual ancestors, unless it is already included. """ add = True for j, va in enumerate(vancestors): if issubclass(va, a): add = False break if issubclass(a, va): vancestors[j] = a add = False if add: vancestors.append(a) # inspired from simplegeneric by P.J. Eby and functools.singledispatch def dispatch_on(*dispatch_args): """ Factory of decorators turning a function into a generic function dispatching on the given arguments. """ assert dispatch_args, 'No dispatch args passed' dispatch_str = '(%s,)' % ', '.join(dispatch_args) def check(arguments, wrong=operator.ne, msg=''): """Make sure one passes the expected number of arguments""" if wrong(len(arguments), len(dispatch_args)): raise TypeError('Expected %d arguments, got %d%s' % (len(dispatch_args), len(arguments), msg)) def gen_func_dec(func): """Decorator turning a function into a generic function""" # first check the dispatch arguments argset = set(getfullargspec(func).args) if not set(dispatch_args) <= argset: raise NameError('Unknown dispatch arguments %s' % dispatch_str) typemap = {} def vancestors(*types): """ Get a list of sets of virtual ancestors for the given types """ check(types) ras = [[] for _ in range(len(dispatch_args))] for types_ in typemap: for t, type_, ra in zip(types, types_, ras): if issubclass(t, type_) and type_ not in t.__mro__: append(type_, ra) return [set(ra) for ra in ras] def ancestors(*types): """ Get a list of virtual MROs, one for each type """ check(types) lists = [] for t, vas in zip(types, vancestors(*types)): n_vas = len(vas) if n_vas > 1: raise RuntimeError( 'Ambiguous dispatch for %s: %s' % (t, vas)) elif n_vas == 1: va, = vas mro = type('t', (t, va), {}).__mro__[1:] else: mro = t.__mro__ lists.append(mro[:-1]) # discard t and object return lists def register(*types): """ Decorator to register an implementation for the given types """ check(types) def dec(f): check(getfullargspec(f).args, operator.lt, ' in ' + f.__name__) typemap[types] = f return f return dec def dispatch_info(*types): """ An utility to introspect the dispatch algorithm """ check(types) lst = [] for anc in itertools.product(*ancestors(*types)): lst.append(tuple(a.__name__ for a in anc)) return lst def _dispatch(dispatch_args, *args, **kw): types = tuple(type(arg) for arg in dispatch_args) try: # fast path f = typemap[types] except KeyError: pass else: return f(*args, **kw) combinations = itertools.product(*ancestors(*types)) next(combinations) # the first one has been already tried for types_ in combinations: f = typemap.get(types_) if f is not None: return f(*args, **kw) # else call the default implementation return func(*args, **kw) return FunctionMaker.create( func, 'return _f_(%s, %%(shortsignature)s)' % dispatch_str, dict(_f_=_dispatch), register=register, default=func, typemap=typemap, vancestors=vancestors, ancestors=ancestors, dispatch_info=dispatch_info, __wrapped__=func) gen_func_dec.__name__ = 'dispatch_on' + dispatch_str return gen_func_dec decorator-4.0.6/setup.cfg0000664000175000017500000000017112632446721016372 0ustar michelemichele00000000000000[bdist_wheel] universal = 1 [upload_docs] upload-dir = docs [egg_info] tag_date = 0 tag_svn_revision = 0 tag_build = decorator-4.0.6/performance.sh0000664000175000017500000000033112554406023017376 0ustar michelemichele00000000000000python3 -m timeit -s " from decorator import decorator @decorator def do_nothing(func, *args, **kw): return func(*args, **kw) @do_nothing def f(): pass " "f()" python3 -m timeit -s " def f(): pass " "f()" decorator-4.0.6/docs/0000775000175000017500000000000012632446721015502 5ustar michelemichele00000000000000decorator-4.0.6/docs/README.rst0000664000175000017500000000273012601131557017165 0ustar michelemichele00000000000000Decorator module ================= :Author: Michele Simionato :E-mail: michele.simionato@gmail.com :Requires: Python 2.6+ :Download page: http://pypi.python.org/pypi/decorator :Installation: ``pip install decorator`` :License: BSD license Installation ------------- If you are lazy, just perform `$ pip install decorator` which will install just the module on your system. If you prefer to install the full distribution from source, including the documentation, download the tarball_, unpack it and run `$ python setup.py install` in the main directory, possibly as superuser. .. _tarball: http://pypi.python.org/pypi/decorator Testing -------- Run `$ python src/tests/test.py -v` or (if you have setuptools installed) `$ python setup.py test` Notice that you may run into trouble if in your system there is an older version of the decorator module; in such a case remove the old version. It is safe even to copy the module `decorator.py` over an existing one, since version 4.0 is backward-compatible. Documentation -------------- There are various versions of the documentation: - `HTML version`_ - `PDF version`_ .. _HTML version: http://pythonhosted.org/decorator/documentation.html .. _PDF version: https://github.com/micheles/decorator/blob/4.0.4/documentation.pdf Repository --------------- The project is hosted on GitHub. You can look at the source here: https://github.com/micheles/decorator decorator-4.0.6/CHANGES.txt0000664000175000017500000001617112632446433016371 0ustar michelemichele00000000000000HISTORY -------- 4.0.6 Removed a file x.py accidentally entered in the tarball (2015/12/11) 4.0.5 Documented a quirk signaled by David Goldstein when writing decorators for functions with keyword arguments. Avoided copying the globals, as signaled by Benjamin Peterson (2015/12/09) 4.0.4 Included a patch from Zev Benjamin: now decorated functions play well with cProfile (2015/09/25) 4.0.3 Added a warning about the memoize example, as requested by Robert Buchholz (2015/09/25) 4.0.2 docs/README.rst was not included in MANIFEST.in by accident, thus breaking the source installation (2015/07/28) 4.0.1 Added docs directory and upload_docs command. Fixed bug with `__qualname__`, reported by Lucian Petrut (2015/07/28) 4.0.0 Removed the need for 2to3 by dropping the support for Python 2.5. Added a MANIFEST.in file and produced a proper wheel. Improved the integration with setuptools so that `python setup.py test` works. Reworked the documentation and introduced `decorator.decorated`. Removed any dependence from `inspect.getargspec`, which is deprecated in Python 3.5, as signaled by Ralf Gommers. Fixed `contextmanager` to work with Python 3.5. Copied the `__qualname__` attribute, as requested by Frazer McLean. Added a `dispatch_on` facility to implement generic functions. (2015/07/24) 3.4.2 Same as 3.4.1, re-uploaded to PyPI (2015-03-22) 3.4.1 Ported the repository from GoogleCode to GitHub and added Travis CI support. Tests are executed with the new command `python test.py -v`. setuptools is now mandatory in Python 3. The suggested installation tool is now `pip`, not `easy_install`. Supported IronPython and other Python implementations without sys._getframe, as requested by Doug Blank (2015/03/16) 3.4.0 Added the ability to use classes and generic callables as callers and implemented a signature-preserving contexmanager decorator. Fixed a bug with the signature f(**kw) in Python 3 and fixed a couple of doctests broken by Python 3.3, both issues pointed out by Dominic Sacré (18/10/2012) 3.3.3 Fixed a bug with kwonlyargs for Python 3, submitted by Chris Ellison (23/04/2012) 3.3.2 Fixed a bug with __kwdefaults__ for Python 3, submitted by Chris Ellison (01/09/2011) 3.3.1 Fixed a doctest broken for Python 3.2, as noted by Arfrever Frehtes Taifersar Arahesis; changed the name of the attribute ``undecorated`` to ``__wrapped__``, by following the Python 3.2 convention, as requested by Ram Rachum; added the Python 3 classifier to setup.py (22/04/2011) 3.3. Added support for function annotations (1/1/2011) 3.2.1. Now the .func_globals of the decorated function are the same of the undecorated function, as requested by Paul Ollis (28/12/2010) 3.2. Added __version__ (thanks to Gregg Lind), removed functionality which has been deprecated for years, removed the confusing decorator_factory example and added official support for Python 3 (requested by Claus Klein). Moved the documentation from PyPI to googlecode (22/05/2010) 3.1.2. Added attributes args, varargs, keywords and arg0, ..., argN to FunctionMaker objects generated from a function; fixed another Pylons-breaking bug signaled by Lawrence Oluyede (25/08/2009) 3.1.1. Fixed a bug which was breaking Pylons, signaled by Gabriel de Perthuis, and added a test for it. (18/08/2009) 3.1. Added decorator.factory, an easy way to define families of decorators (requested by various users, including David Laban). Refactored the FunctionMaker class and added an easier to use .create classmethod. Internally, functools.partial is used for Python >= 2.5 (16/08/2009) 3.0.1. Improved the error message in case a bound/unbound method is passed instead of a function and documented this case; that should make life easier for users like Gustavo Nerea (16/02/2009) 3.0. New major version introducing ``FunctionMaker`` and the two-argument syntax for ``decorator``. Moreover, added support for getting the source code. This version is Python 3.0 ready. Major overhaul of the documentation, now hosted on http://packages.python.org/decorator (14/12/2008) 2.3.2. Small optimization in the code for decorator factories. First version with the code uploaded to PyPI (01/12/2008) 2.3.1. Set the zipsafe flag to False, since I want my users to have the source, not a zipped egg (25/07/2008) 2.3.0. Added support for writing decorator factories with minimal effort (feature requested by Matthew Wilson); implemented it by enhancing 'decorator' to a Python 2.6 class decorator (10/07/2008) 2.2.0. Added a note on 'inspect.getsource' not working for decorated functions; referenced PEP 326; highlighted the snippets in the documentation with pygments; slightly simplified the code (31/07/2007) 2.1.0. Replaced the utility 'update_wrapper' with 'new_wrapper' and updated the documentation accordingly; fixed and improved the doctester argument parsing, signaled by Sam Wyse (3/07/2007) 2.0.1. Included the licence in the source code too; fixed a versioning issue by adding the version number to the zip file and fixing the link to it on the web page, thanks to Philip Jenvey (17/02/2007) 2.0. Rewritten and simplified the implementation; broken compatibility with previous versions (in minor ways); added the utility function 'update_wrapper' instead of 'newfunc' (13/01/2007) 1.1. 'decorator' instances now have attributes __name__, __doc__, __module__ and __dict__ coming from the associated caller function; included the licence into the documentation (02/12/2006) 1.0. Added LICENSE.txt; added a setuptools-friendly setup.py script contributed by Luke Arno (10/08/2006) 0.8.1. Minor fixes to the documentation (21/06/2006) 0.8. Improved the documentation, added the 'caveats' section (16/06/2006) 0.7.1. Improved the tail_recursive example (15/05/2006) 0.7. Renamed 'copyfunc' into 'newfunc' and added the ability to copy the signature from a model function; improved '_decorator' to set the '__module__' attribute too, with the intent of improving error messages; updated the documentation (10/05/2006) 0.6. Changed decorator.__call__ so that the module somewhat works even for Python 2.3 (but the signature-preserving feature is lost) (20/12/2005) 0.5.2. Minor changes to the documentation; improved 'getattr_' and shortened 'locked' (28/06/2005) 0.5.1. Minor corrections to the documentation (20/05/2005) 0.5. Fixed a bug with out-of-the-mind signatures, added a check for reserved names in the argument list and simplified the code (thanks to Duncan Booth) (19/05/2005) 0.4.1. Fixed a typo in the documentation (thanks to Anthon van der Neut) (17/05/2005) 0.4. Added getinfo, some tests and improved the documentation (12/05/2005) 0.3. Simplified copyfunc, renamed deferred to delayed and added the nonblocking example (10/05/2005) 0.2. Added copyfunc, improved the multithreading examples, improved the doctester program (09/05/2005) 0.1.1. Added the license specification and two docstrings (06/05/2005) 0.1. Initial release (04/05/2005) decorator-4.0.6/setup.py0000664000175000017500000000234712555576003016273 0ustar michelemichele00000000000000from setuptools import setup dic = {} exec(open('src/decorator.py').read(), dic) VERSION = dic['__version__'] if __name__ == '__main__': setup(name='decorator', version=VERSION, description='Better living through Python with decorators', long_description=open('docs/README.rst').read(), author='Michele Simionato', author_email='michele.simionato@gmail.com', url='https://github.com/micheles/decorator', license="new BSD License", package_dir={'': 'src'}, py_modules=['decorator'], keywords="decorators generic utility", platforms=["All"], classifiers=['Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Topic :: Software Development :: Libraries', 'Topic :: Utilities'], test_suite='tests', zip_safe=False) decorator-4.0.6/documentation.pdf0000664000175000017500000117300612632446622020126 0ustar michelemichele00000000000000%PDF-1.4 %“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com 1 0 obj << /F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 50 0 R /F5 54 0 R /F6 55 0 R >> endobj 2 0 obj << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >> endobj 3 0 obj << /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font >> endobj 4 0 obj << /BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font >> endobj 5 0 obj << /A << /S /URI /Type /Action /URI (mailto:michele.simionato@gmail.com) >> /Border [ 0 0 0 ] /Rect [ 153.7323 704.0236 289.4623 716.0236 ] /Subtype /Link /Type /Annot >> endobj 6 0 obj << /A << /S /URI /Type /Action /URI (http://pypi.python.org/pypi/decorator/4.0.5) >> /Border [ 0 0 0 ] /Rect [ 153.7323 659.7736 338.2823 671.7736 ] /Subtype /Link /Type /Annot >> endobj 7 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 52 0 R /XYZ 62.69291 765.0236 0 ] /Rect [ 62.69291 560.0236 121.0229 572.0236 ] /Subtype /Link /Type /Annot >> endobj 8 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 52 0 R /XYZ 62.69291 765.0236 0 ] /Rect [ 527.0227 560.7736 532.5827 572.7736 ] /Subtype /Link /Type /Annot >> endobj 9 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 52 0 R /XYZ 62.69291 582.0236 0 ] /Rect [ 62.69291 542.0236 117.3029 554.0236 ] /Subtype /Link /Type /Annot >> endobj 10 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 52 0 R /XYZ 62.69291 582.0236 0 ] /Rect [ 527.0227 542.7736 532.5827 554.7736 ] /Subtype /Link /Type /Annot >> endobj 11 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 52 0 R /XYZ 62.69291 357.0236 0 ] /Rect [ 62.69291 524.0236 182.7229 536.0236 ] /Subtype /Link /Type /Annot >> endobj 12 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 52 0 R /XYZ 62.69291 357.0236 0 ] /Rect [ 527.0227 524.7736 532.5827 536.7736 ] /Subtype /Link /Type /Annot >> endobj 13 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 57 0 R /XYZ 62.69291 729.0236 0 ] /Rect [ 62.69291 506.0236 114.3629 518.0236 ] /Subtype /Link /Type /Annot >> endobj 14 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 57 0 R /XYZ 62.69291 729.0236 0 ] /Rect [ 527.0227 506.7736 532.5827 518.7736 ] /Subtype /Link /Type /Annot >> endobj 15 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 57 0 R /XYZ 62.69291 492.0236 0 ] /Rect [ 62.69291 488.0236 183.2629 500.0236 ] /Subtype /Link /Type /Annot >> endobj 16 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 57 0 R /XYZ 62.69291 492.0236 0 ] /Rect [ 527.0227 488.7736 532.5827 500.7736 ] /Subtype /Link /Type /Annot >> endobj 17 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 58 0 R /XYZ 62.69291 326.2236 0 ] /Rect [ 62.69291 470.0236 122.1429 482.0236 ] /Subtype /Link /Type /Annot >> endobj 18 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 58 0 R /XYZ 62.69291 326.2236 0 ] /Rect [ 527.0227 470.7736 532.5827 482.7736 ] /Subtype /Link /Type /Annot >> endobj 19 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 59 0 R /XYZ 62.69291 298.2236 0 ] /Rect [ 62.69291 452.0236 69.91291 464.0236 ] /Subtype /Link /Type /Annot >> endobj 20 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 59 0 R /XYZ 62.69291 298.2236 0 ] /Rect [ 72.69291 452.0236 102.6929 464.0236 ] /Subtype /Link /Type /Annot >> endobj 21 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 59 0 R /XYZ 62.69291 298.2236 0 ] /Rect [ 108.6929 452.0236 154.8129 464.0236 ] /Subtype /Link /Type /Annot >> endobj 22 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 59 0 R /XYZ 62.69291 298.2236 0 ] /Rect [ 527.0227 452.7736 532.5827 464.7736 ] /Subtype /Link /Type /Annot >> endobj 23 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 61 0 R /XYZ 62.69291 424.2236 0 ] /Rect [ 62.69291 434.0236 164.3629 446.0236 ] /Subtype /Link /Type /Annot >> endobj 24 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 61 0 R /XYZ 62.69291 424.2236 0 ] /Rect [ 527.0227 434.7736 532.5827 446.7736 ] /Subtype /Link /Type /Annot >> endobj 25 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 62 0 R /XYZ 62.69291 594.6236 0 ] /Rect [ 62.69291 416.0236 176.6929 428.0236 ] /Subtype /Link /Type /Annot >> endobj 26 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 62 0 R /XYZ 62.69291 594.6236 0 ] /Rect [ 527.0227 416.7736 532.5827 428.7736 ] /Subtype /Link /Type /Annot >> endobj 27 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 62 0 R /XYZ 62.69291 146.8236 0 ] /Rect [ 62.69291 398.0236 110.6929 410.0236 ] /Subtype /Link /Type /Annot >> endobj 28 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 62 0 R /XYZ 62.69291 146.8236 0 ] /Rect [ 527.0227 398.7736 532.5827 410.7736 ] /Subtype /Link /Type /Annot >> endobj 29 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 63 0 R /XYZ 62.69291 290.6236 0 ] /Rect [ 62.69291 380.0236 146.6929 392.0236 ] /Subtype /Link /Type /Annot >> endobj 30 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 63 0 R /XYZ 62.69291 290.6236 0 ] /Rect [ 527.0227 380.7736 532.5827 392.7736 ] /Subtype /Link /Type /Annot >> endobj 31 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 64 0 R /XYZ 62.69291 410.6236 0 ] /Rect [ 62.69291 362.0236 139.9329 374.0236 ] /Subtype /Link /Type /Annot >> endobj 32 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 64 0 R /XYZ 62.69291 410.6236 0 ] /Rect [ 527.0227 362.7736 532.5827 374.7736 ] /Subtype /Link /Type /Annot >> endobj 33 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 65 0 R /XYZ 62.69291 503.8236 0 ] /Rect [ 62.69291 344.0236 80.47291 356.0236 ] /Subtype /Link /Type /Annot >> endobj 34 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 65 0 R /XYZ 62.69291 503.8236 0 ] /Rect [ 83.25291 344.0236 161.2529 356.0236 ] /Subtype /Link /Type /Annot >> endobj 35 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 65 0 R /XYZ 62.69291 503.8236 0 ] /Rect [ 167.2529 344.0236 192.2729 356.0236 ] /Subtype /Link /Type /Annot >> endobj 36 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 65 0 R /XYZ 62.69291 503.8236 0 ] /Rect [ 521.4627 344.7736 532.5827 356.7736 ] /Subtype /Link /Type /Annot >> endobj 37 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 67 0 R /XYZ 62.69291 521.8236 0 ] /Rect [ 62.69291 326.0236 177.1629 338.0236 ] /Subtype /Link /Type /Annot >> endobj 38 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 67 0 R /XYZ 62.69291 521.8236 0 ] /Rect [ 521.4627 326.7736 532.5827 338.7736 ] /Subtype /Link /Type /Annot >> endobj 39 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 69 0 R /XYZ 62.69291 715.8236 0 ] /Rect [ 62.69291 308.0236 228.2829 320.0236 ] /Subtype /Link /Type /Annot >> endobj 40 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 69 0 R /XYZ 62.69291 715.8236 0 ] /Rect [ 521.4627 308.7736 532.5827 320.7736 ] /Subtype /Link /Type /Annot >> endobj 41 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 70 0 R /XYZ 62.69291 287.0236 0 ] /Rect [ 62.69291 290.0236 144.3729 302.0236 ] /Subtype /Link /Type /Annot >> endobj 42 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 70 0 R /XYZ 62.69291 287.0236 0 ] /Rect [ 521.4627 290.7736 532.5827 302.7736 ] /Subtype /Link /Type /Annot >> endobj 43 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 75 0 R /XYZ 62.69291 659.8236 0 ] /Rect [ 62.69291 272.0236 251.0829 284.0236 ] /Subtype /Link /Type /Annot >> endobj 44 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 75 0 R /XYZ 62.69291 659.8236 0 ] /Rect [ 521.4627 272.7736 532.5827 284.7736 ] /Subtype /Link /Type /Annot >> endobj 45 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 78 0 R /XYZ 62.69291 765.0236 0 ] /Rect [ 62.69291 254.0236 174.3929 266.0236 ] /Subtype /Link /Type /Annot >> endobj 46 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 78 0 R /XYZ 62.69291 765.0236 0 ] /Rect [ 521.4627 254.7736 532.5827 266.7736 ] /Subtype /Link /Type /Annot >> endobj 47 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 80 0 R /XYZ 62.69291 494.6236 0 ] /Rect [ 62.69291 236.0236 106.0329 248.0236 ] /Subtype /Link /Type /Annot >> endobj 48 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 80 0 R /XYZ 62.69291 494.6236 0 ] /Rect [ 521.4627 236.7736 532.5827 248.7736 ] /Subtype /Link /Type /Annot >> endobj 49 0 obj << /Annots [ 5 0 R 6 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R 27 0 R 28 0 R 29 0 R 30 0 R 31 0 R 32 0 R 33 0 R 34 0 R 35 0 R 36 0 R 37 0 R 38 0 R 39 0 R 40 0 R 41 0 R 42 0 R 43 0 R 44 0 R 45 0 R 46 0 R 47 0 R 48 0 R ] /Contents 104 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 50 0 obj << /BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F4 /Subtype /Type1 /Type /Font >> endobj 51 0 obj << /A << /S /URI /Type /Action /URI (http://pythonwheels.com/) >> /Border [ 0 0 0 ] /Rect [ 106.4829 630.0236 133.6029 642.0236 ] /Subtype /Link /Type /Annot >> endobj 52 0 obj << /Annots [ 51 0 R ] /Contents 105 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 53 0 obj << /A << /S /URI /Type /Action /URI (http://www.python.org/moin/PythonDecoratorLibrary) >> /Border [ 0 0 0 ] /Rect [ 219.6428 417.0236 449.1728 429.0236 ] /Subtype /Link /Type /Annot >> endobj 54 0 obj << /BaseFont /Courier-Bold /Encoding /WinAnsiEncoding /Name /F5 /Subtype /Type1 /Type /Font >> endobj 55 0 obj << /BaseFont /Courier-Oblique /Encoding /WinAnsiEncoding /Name /F6 /Subtype /Type1 /Type /Font >> endobj 56 0 obj << /A << /S /URI /Type /Action /URI (https://docs.python.org/3/library/functools.html#functools.update_wrapper) >> /Border [ 0 0 0 ] /Rect [ 143.9057 177.8236 261.4814 189.8236 ] /Subtype /Link /Type /Annot >> endobj 57 0 obj << /Annots [ 53 0 R 56 0 R ] /Contents 106 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 58 0 obj << /Contents 107 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 59 0 obj << /Contents 108 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 60 0 obj << /A << /S /URI /Type /Action /URI (http://www.python.org/dev/peps/pep-3107/) >> /Border [ 0 0 0 ] /Rect [ 231.6368 385.2236 323.0741 397.2236 ] /Subtype /Link /Type /Annot >> endobj 61 0 obj << /Annots [ 60 0 R ] /Contents 109 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 62 0 obj << /Contents 110 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 63 0 obj << /Contents 111 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 64 0 obj << /Contents 112 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 65 0 obj << /Contents 113 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 66 0 obj << /A << /S /URI /Type /Action /URI (http://bugs.python.org/issue1764286) >> /Border [ 0 0 0 ] /Rect [ 133.3162 207.2236 172.2473 219.2236 ] /Subtype /Link /Type /Annot >> endobj 67 0 obj << /Annots [ 66 0 R ] /Contents 114 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 68 0 obj << /A << /S /URI /Type /Action /URI (http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496691) >> /Border [ 0 0 0 ] /Rect [ 62.69291 383.6236 363.4029 395.6236 ] /Subtype /Link /Type /Annot >> endobj 69 0 obj << /Annots [ 68 0 R ] /Contents 115 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 70 0 obj << /Contents 116 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 71 0 obj << /Contents 117 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 72 0 obj << /Contents 118 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 73 0 obj << /A << /S /URI /Type /Action /URI (http://www.python.org/2.3/mro.html) >> /Border [ 0 0 0 ] /Rect [ 330.4156 683.8236 355.3935 695.8236 ] /Subtype /Link /Type /Annot >> endobj 74 0 obj << /A << /S /URI /Type /Action /URI (http://www.python.org/2.3/mro.html) >> /Border [ 0 0 0 ] /Rect [ 284.1108 454.4236 309.8555 466.4236 ] /Subtype /Link /Type /Annot >> endobj 75 0 obj << /Annots [ 73 0 R 74 0 R ] /Contents 119 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 76 0 obj << /Contents 120 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 77 0 obj << /Contents 121 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 78 0 obj << /Contents 122 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 79 0 obj << /Contents 123 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 80 0 obj << /Contents 124 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 103 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 81 0 obj << /Outlines 83 0 R /PageLabels 125 0 R /PageMode /UseNone /Pages 103 0 R /Type /Catalog >> endobj 82 0 obj << /Author (Michele Simionato) /CreationDate (D:20151211051408-01'00') /Creator (\(unspecified\)) /Keywords () /Producer (ReportLab PDF Library - www.reportlab.com) /Subject (\(unspecified\)) /Title (The decorator module) >> endobj 83 0 obj << /Count 19 /First 84 0 R /Last 102 0 R /Type /Outlines >> endobj 84 0 obj << /Dest [ 52 0 R /XYZ 62.69291 765.0236 0 ] /Next 85 0 R /Parent 83 0 R /Title (Introduction) >> endobj 85 0 obj << /Dest [ 52 0 R /XYZ 62.69291 582.0236 0 ] /Next 86 0 R /Parent 83 0 R /Prev 84 0 R /Title (What's new) >> endobj 86 0 obj << /Dest [ 52 0 R /XYZ 62.69291 357.0236 0 ] /Next 87 0 R /Parent 83 0 R /Prev 85 0 R /Title (Usefulness of decorators) >> endobj 87 0 obj << /Dest [ 57 0 R /XYZ 62.69291 729.0236 0 ] /Next 88 0 R /Parent 83 0 R /Prev 86 0 R /Title (Definitions) >> endobj 88 0 obj << /Dest [ 57 0 R /XYZ 62.69291 492.0236 0 ] /Next 89 0 R /Parent 83 0 R /Prev 87 0 R /Title (Statement of the problem) >> endobj 89 0 obj << /Dest [ 58 0 R /XYZ 62.69291 326.2236 0 ] /Next 90 0 R /Parent 83 0 R /Prev 88 0 R /Title (The solution) >> endobj 90 0 obj << /Dest [ 59 0 R /XYZ 62.69291 298.2236 0 ] /Next 91 0 R /Parent 83 0 R /Prev 89 0 R /Title (A trace decorator) >> endobj 91 0 obj << /Dest [ 61 0 R /XYZ 62.69291 424.2236 0 ] /Next 92 0 R /Parent 83 0 R /Prev 90 0 R /Title (Function annotations) >> endobj 92 0 obj << /Dest [ 62 0 R /XYZ 62.69291 594.6236 0 ] /Next 93 0 R /Parent 83 0 R /Prev 91 0 R /Title (decorator.decorator) >> endobj 93 0 obj << /Dest [ 62 0 R /XYZ 62.69291 146.8236 0 ] /Next 94 0 R /Parent 83 0 R /Prev 92 0 R /Title (blocking) >> endobj 94 0 obj << /Dest [ 63 0 R /XYZ 62.69291 290.6236 0 ] /Next 95 0 R /Parent 83 0 R /Prev 93 0 R /Title (decorator\(cls\)) >> endobj 95 0 obj << /Dest [ 64 0 R /XYZ 62.69291 410.6236 0 ] /Next 96 0 R /Parent 83 0 R /Prev 94 0 R /Title (contextmanager) >> endobj 96 0 obj << /Dest [ 65 0 R /XYZ 62.69291 503.8236 0 ] /Next 97 0 R /Parent 83 0 R /Prev 95 0 R /Title (The FunctionMaker class) >> endobj 97 0 obj << /Dest [ 67 0 R /XYZ 62.69291 521.8236 0 ] /Next 98 0 R /Parent 83 0 R /Prev 96 0 R /Title (Getting the source code) >> endobj 98 0 obj << /Dest [ 69 0 R /XYZ 62.69291 715.8236 0 ] /Next 99 0 R /Parent 83 0 R /Prev 97 0 R /Title (Dealing with third party decorators) >> endobj 99 0 obj << /Dest [ 70 0 R /XYZ 62.69291 287.0236 0 ] /Next 100 0 R /Parent 83 0 R /Prev 98 0 R /Title (Multiple dispatch) >> endobj 100 0 obj << /Dest [ 75 0 R /XYZ 62.69291 659.8236 0 ] /Next 101 0 R /Parent 83 0 R /Prev 99 0 R /Title (Generic functions and virtual ancestors) >> endobj 101 0 obj << /Dest [ 78 0 R /XYZ 62.69291 765.0236 0 ] /Next 102 0 R /Parent 83 0 R /Prev 100 0 R /Title (Caveats and limitations) >> endobj 102 0 obj << /Dest [ 80 0 R /XYZ 62.69291 494.6236 0 ] /Parent 83 0 R /Prev 101 0 R /Title (LICENSE) >> endobj 103 0 obj << /Count 21 /Kids [ 49 0 R 52 0 R 57 0 R 58 0 R 59 0 R 61 0 R 62 0 R 63 0 R 64 0 R 65 0 R 67 0 R 69 0 R 70 0 R 71 0 R 72 0 R 75 0 R 76 0 R 77 0 R 78 0 R 79 0 R 80 0 R ] /Type /Pages >> endobj 104 0 obj << /Length 7563 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 741.0236 cm q BT 1 0 0 1 0 4 Tm 118.8249 0 Td 24 TL /F2 20 Tf 0 0 0 rg (The ) Tj /F3 20 Tf 0 0 0 rg (decorator ) Tj /F2 20 Tf 0 0 0 rg (module) Tj T* -118.8249 0 Td ET Q Q q 1 0 0 1 62.69291 716.0236 cm 0 0 0 rg BT /F1 10 Tf 12 TL ET q 1 0 0 1 6 3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 36.93937 0 Td (Author:) Tj T* -36.93937 0 Td ET Q Q q 1 0 0 1 91.03937 3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Michele Simionato) Tj T* ET Q Q q Q Q q 1 0 0 1 62.69291 701.0236 cm 0 0 0 rg BT /F1 10 Tf 12 TL ET q 1 0 0 1 6 3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 39.69937 0 Td (E-mail:) Tj T* -39.69937 0 Td ET Q Q q 1 0 0 1 91.03937 3 cm q BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 .501961 rg (michele.simionato@gmail.com) Tj T* ET Q Q q Q Q q 1 0 0 1 62.69291 686.0236 cm 0 0 0 rg BT /F1 10 Tf 12 TL ET q 1 0 0 1 6 3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 33.02937 0 Td (Version:) Tj T* -33.02937 0 Td ET Q Q q 1 0 0 1 91.03937 3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (4.0.5 \(2015-12-11\)) Tj T* ET Q Q q Q Q q 1 0 0 1 62.69291 671.0236 cm 0 0 0 rg BT /F1 10 Tf 12 TL ET q 1 0 0 1 6 3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 25.81937 0 Td (Supports:) Tj T* -25.81937 0 Td ET Q Q q 1 0 0 1 91.03937 3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Python 2.6, 2.7, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5) Tj T* ET Q Q q Q Q q 1 0 0 1 62.69291 644.0236 cm 0 0 0 rg BT /F1 10 Tf 12 TL ET q 1 0 0 1 6 3 cm q 0 0 0 rg BT 1 0 0 1 0 14 Tm /F2 10 Tf 12 TL 25.25937 0 Td (Download) Tj T* 21.11 0 Td (page:) Tj T* -46.36937 0 Td ET Q Q q 1 0 0 1 91.03937 15 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (http://pypi.python.org/pypi/decorator/4.0.5) Tj T* ET Q Q q Q Q q 1 0 0 1 62.69291 629.0236 cm 0 0 0 rg BT /F1 10 Tf 12 TL ET q 1 0 0 1 6 3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 16.91937 0 Td (Installation:) Tj T* -16.91937 0 Td ET Q Q q 1 0 0 1 91.03937 3 cm q BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 0 rg (pip) Tj ( ) Tj (install) Tj ( ) Tj (decorator) Tj T* ET Q Q q Q Q q 1 0 0 1 62.69291 614.0236 cm 0 0 0 rg BT /F1 10 Tf 12 TL ET q 1 0 0 1 6 3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 32.46937 0 Td (License:) Tj T* -32.46937 0 Td ET Q Q q 1 0 0 1 91.03937 3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (BSD license) Tj T* ET Q Q q Q Q q 1 0 0 1 62.69291 581.0236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Contents) Tj T* ET Q Q q 1 0 0 1 62.69291 233.0236 cm 0 0 0 rg BT /F1 10 Tf 12 TL ET q 1 0 0 1 0 327 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Introduction) Tj T* ET Q Q q 1 0 0 1 397.8898 327 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (2) Tj T* -66.44 0 Td ET Q Q q 1 0 0 1 0 309 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (What's new) Tj T* ET Q Q q 1 0 0 1 397.8898 309 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (2) Tj T* -66.44 0 Td ET Q Q q 1 0 0 1 0 291 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Usefulness of decorators) Tj T* ET Q Q q 1 0 0 1 397.8898 291 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (2) Tj T* -66.44 0 Td ET Q Q q 1 0 0 1 0 273 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Definitions) Tj T* ET Q Q q 1 0 0 1 397.8898 273 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (3) Tj T* -66.44 0 Td ET Q Q q 1 0 0 1 0 255 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Statement of the problem) Tj T* ET Q Q q 1 0 0 1 397.8898 255 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (3) Tj T* -66.44 0 Td ET Q Q q 1 0 0 1 0 237 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (The solution) Tj T* ET Q Q q 1 0 0 1 397.8898 237 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (4) Tj T* -66.44 0 Td ET Q Q q 1 0 0 1 0 219 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (A ) Tj /F3 10 Tf 0 0 0 rg (trace ) Tj /F2 10 Tf 0 0 .501961 rg (decorator) Tj T* ET Q Q q 1 0 0 1 397.8898 219 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (5) Tj T* -66.44 0 Td ET Q Q q 1 0 0 1 0 201 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Function annotations) Tj T* ET Q Q q 1 0 0 1 397.8898 201 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (6) Tj T* -66.44 0 Td ET Q Q q 1 0 0 1 0 183 cm q BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 0 rg (decorator.decorator) Tj T* ET Q Q q 1 0 0 1 397.8898 183 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (7) Tj T* -66.44 0 Td ET Q Q q 1 0 0 1 0 165 cm q BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 0 rg (blocking) Tj T* ET Q Q q 1 0 0 1 397.8898 165 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (7) Tj T* -66.44 0 Td ET Q Q q 1 0 0 1 0 147 cm q BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 0 rg (decorator\(cls\)) Tj T* ET Q Q q 1 0 0 1 397.8898 147 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (8) Tj T* -66.44 0 Td ET Q Q q 1 0 0 1 0 129 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (contextmanager) Tj T* ET Q Q q 1 0 0 1 397.8898 129 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (9) Tj T* -66.44 0 Td ET Q Q q 1 0 0 1 0 111 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (The ) Tj /F3 10 Tf 0 0 0 rg (FunctionMaker ) Tj /F2 10 Tf 0 0 .501961 rg (class) Tj T* ET Q Q q 1 0 0 1 397.8898 111 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 60.88 0 Td (10) Tj T* -60.88 0 Td ET Q Q q 1 0 0 1 0 93 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Getting the source code) Tj T* ET Q Q q 1 0 0 1 397.8898 93 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 60.88 0 Td (11) Tj T* -60.88 0 Td ET Q Q q 1 0 0 1 0 75 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Dealing with third party decorators) Tj T* ET Q Q q 1 0 0 1 397.8898 75 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 60.88 0 Td (12) Tj T* -60.88 0 Td ET Q Q q 1 0 0 1 0 57 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Multiple dispatch) Tj T* ET Q Q q 1 0 0 1 397.8898 57 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 60.88 0 Td (13) Tj T* -60.88 0 Td ET Q Q q 1 0 0 1 0 39 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Generic functions and virtual ancestors) Tj T* ET Q Q q 1 0 0 1 397.8898 39 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 60.88 0 Td (16) Tj T* -60.88 0 Td ET Q Q q 1 0 0 1 0 21 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Caveats and limitations) Tj T* ET Q Q q 1 0 0 1 397.8898 21 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 60.88 0 Td (19) Tj T* -60.88 0 Td ET Q Q q 1 0 0 1 0 3 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (LICENSE) Tj T* ET Q Q q 1 0 0 1 397.8898 3 cm q 0 0 .501961 rg 0 0 .501961 RG BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 60.88 0 Td (21) Tj T* -60.88 0 Td ET Q Q q Q Q endstream endobj 105 0 obj << /Length 7225 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 744.0236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Introduction) Tj T* ET Q Q q 1 0 0 1 62.69291 594.0236 cm q BT 1 0 0 1 0 134 Tm 1.033876 Tw 12 TL /F1 10 Tf 0 0 0 rg (The decorator module is over ten years old, but still alive and kicking. It is used by several frameworks) Tj T* 0 Tw 1.401098 Tw (\(IPython, scipy, authkit, pylons, pycuda, sugar, ...\) and has been stable for a ) Tj /F4 10 Tf (long ) Tj /F1 10 Tf (time. It is your best) Tj T* 0 Tw 1.50686 Tw (option if you want to preserve the signature of decorated functions in a consistent way across Python) Tj T* 0 Tw .103876 Tw (releases. Version 4.0 is fully compatible with the past, except for one thing: support for Python 2.4 and 2.5) Tj T* 0 Tw 1.399431 Tw (has been dropped. That decision made it possible to use a single code base both for Python 2.X and) Tj T* 0 Tw 6.201984 Tw (Python 3.X. This is a ) Tj /F4 10 Tf (huge ) Tj /F1 10 Tf (bonus, since I could remove over 2,000 lines of duplicated) Tj T* 0 Tw .485366 Tw (documentation/doctests. Having to maintain separate docs for Python 2 and Python 3 effectively stopped) Tj T* 0 Tw .075542 Tw (any development on the module for several years. Moreover, it is now trivial to distribute the module as an) Tj T* 0 Tw .999987 Tw (universal ) Tj 0 0 .501961 rg (wheel ) Tj 0 0 0 rg (since 2to3 is no more required. Since Python 2.5 has been released 9 years ago, I felt) Tj T* 0 Tw .829461 Tw (that it was reasonable to drop the support for it. If you need to support ancient versions of Python, stick) Tj T* 0 Tw 1.438735 Tw (with the decorator module version 3.4.2. This version supports all Python releases from 2.6 up to 3.5,) Tj T* 0 Tw (which currently is still in beta status.) Tj T* ET Q Q q 1 0 0 1 62.69291 561.0236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (What's new) Tj T* ET Q Q q 1 0 0 1 62.69291 471.0236 cm q BT 1 0 0 1 0 74 Tm 2.334692 Tw 12 TL /F1 10 Tf 0 0 0 rg (Since now there is a single manual for all Python versions, I took the occasion for overhauling the) Tj T* 0 Tw .691098 Tw (documentation. Therefore, even if you are an old time user, you may want to read the docs again, since) Tj T* 0 Tw .385318 Tw (several examples have been improved. The packaging has been improved and I am distributing the code) Tj T* 0 Tw 3.941984 Tw (in wheel format too. The integration with setuptools has been improved and now you can use) Tj T* 0 Tw .166412 Tw /F3 10 Tf 0 0 0 rg (python) Tj ( ) Tj (setup.py test ) Tj /F1 10 Tf 0 0 0 rg (to run the tests. A new utility function ) Tj /F3 10 Tf 0 0 0 rg (decorate\(func, caller\) ) Tj /F1 10 Tf 0 0 0 rg (has been) Tj T* 0 Tw 3.003318 Tw (added, doing the same job that in the past was done by ) Tj /F3 10 Tf 0 0 0 rg (decorator\(caller,) Tj ( ) Tj (func\)) Tj /F1 10 Tf 0 0 0 rg (. The old) Tj T* 0 Tw (functionality is still there for compatibility sake, but it is deprecated and not documented anymore.) Tj T* ET Q Q q 1 0 0 1 62.69291 369.0236 cm q BT 1 0 0 1 0 86 Tm 4.582126 Tw 12 TL /F1 10 Tf 0 0 0 rg (Apart from that, there is a new experimental feature. The decorator module now includes an) Tj T* 0 Tw 3.31284 Tw (implementation of generic \(multiple dispatch\) functions. The API is designed to mimic the one of) Tj T* 0 Tw 2.965976 Tw /F3 10 Tf 0 0 0 rg (functools.singledispatch ) Tj /F1 10 Tf 0 0 0 rg (\(introduced in Python 3.4\) but the implementation is much simpler;) Tj T* 0 Tw .889983 Tw (moreover all the decorators involved preserve the signature of the decorated functions. For the moment) Tj T* 0 Tw 4.982927 Tw (the facility is there mostly to exemplify the power of the module. In the future it could be) Tj T* 0 Tw 1.08881 Tw (enhanced/optimized; on the other hand, both its behavior and its API could change. Such is the fate of) Tj T* 0 Tw .537765 Tw (experimental features. In any case it is very short and compact \(less then one hundred lines\) so you can) Tj T* 0 Tw (extract it for your own use. Take it as food for thought.) Tj T* ET Q Q q 1 0 0 1 62.69291 336.0236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Usefulness of decorators) Tj T* ET Q Q q 1 0 0 1 62.69291 270.0236 cm q 0 0 0 rg BT 1 0 0 1 0 50 Tm /F1 10 Tf 12 TL 3.995366 Tw (Python decorators are an interesting example of why syntactic sugar matters. In principle, their) Tj T* 0 Tw .151235 Tw (introduction in Python 2.4 changed nothing, since they do not provide any new functionality which was not) Tj T* 0 Tw 2.238555 Tw (already present in the language. In practice, their introduction has significantly changed the way we) Tj T* 0 Tw .098409 Tw (structure our programs in Python. I believe the change is for the best, and that decorators are a great idea) Tj T* 0 Tw (since:) Tj T* ET Q Q q 1 0 0 1 62.69291 264.0236 cm Q q 1 0 0 1 62.69291 264.0236 cm Q q 1 0 0 1 62.69291 252.0236 cm 0 0 0 rg BT /F1 10 Tf 12 TL ET q 1 0 0 1 6 -3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET Q Q q 1 0 0 1 23 -3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (decorators help reducing boilerplate code;) Tj T* ET Q Q q Q Q q 1 0 0 1 62.69291 246.0236 cm Q q 1 0 0 1 62.69291 234.0236 cm 0 0 0 rg BT /F1 10 Tf 12 TL ET q 1 0 0 1 6 -3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET Q Q q 1 0 0 1 23 -3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (decorators help separation of concerns;) Tj T* ET Q Q q Q Q q 1 0 0 1 62.69291 228.0236 cm Q q 1 0 0 1 62.69291 216.0236 cm 0 0 0 rg BT /F1 10 Tf 12 TL ET q 1 0 0 1 6 -3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET Q Q q 1 0 0 1 23 -3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (decorators enhance readability and maintenability;) Tj T* ET Q Q q Q Q q 1 0 0 1 62.69291 210.0236 cm Q q 1 0 0 1 62.69291 198.0236 cm 0 0 0 rg BT /F1 10 Tf 12 TL ET q 1 0 0 1 6 -3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET Q Q q 1 0 0 1 23 -3 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (decorators are explicit.) Tj T* ET Q Q q Q Q q 1 0 0 1 62.69291 198.0236 cm Q q 1 0 0 1 62.69291 156.0236 cm q 0 0 0 rg BT 1 0 0 1 0 26 Tm /F1 10 Tf 12 TL .848876 Tw (Still, as of now, writing custom decorators correctly requires some experience and it is not as easy as it) Tj T* 0 Tw 1.049269 Tw (could be. For instance, typical implementations of decorators involve nested functions, and we all know) Tj T* 0 Tw (that flat is better than nested.) Tj T* ET Q Q q 1 0 0 1 62.69291 102.0236 cm q BT 1 0 0 1 0 38 Tm 1.093735 Tw 12 TL /F1 10 Tf 0 0 0 rg (The aim of the ) Tj /F3 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf 0 0 0 rg (module it to simplify the usage of decorators for the average programmer,) Tj T* 0 Tw 2.456136 Tw (and to popularize decorators by showing various non-trivial examples. Of course, as all techniques,) Tj T* 0 Tw 2.234987 Tw (decorators can be abused \(I have seen that\) and you should not try to solve every problem with a) Tj T* 0 Tw (decorator, just because you can.) Tj T* ET Q Q endstream endobj 106 0 obj << /Length 12566 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 741.0236 cm q BT 1 0 0 1 0 14 Tm .13561 Tw 12 TL /F1 10 Tf 0 0 0 rg (You may find the source code for all the examples discussed here in the ) Tj /F3 10 Tf 0 0 0 rg (documentation.py ) Tj /F1 10 Tf 0 0 0 rg (file, which) Tj T* 0 Tw (contains the documentation you are reading in the form of doctests.) Tj T* ET Q Q q 1 0 0 1 62.69291 708.0236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Definitions) Tj T* ET Q Q q 1 0 0 1 62.69291 666.0236 cm q 0 0 0 rg BT 1 0 0 1 0 26 Tm /F1 10 Tf 12 TL 2.37561 Tw (Technically speaking, any Python object which can be called with one argument can be used as a) Tj T* 0 Tw .472339 Tw (decorator. However, this definition is somewhat too large to be really useful. It is more convenient to split) Tj T* 0 Tw (the generic class of decorators in two subclasses:) Tj T* ET Q Q q 1 0 0 1 62.69291 660.0236 cm Q q 1 0 0 1 62.69291 660.0236 cm Q q 1 0 0 1 62.69291 636.0236 cm 0 0 0 rg BT /F1 10 Tf 12 TL ET q 1 0 0 1 6 9 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET Q Q q 1 0 0 1 23 -3 cm q BT 1 0 0 1 0 14 Tm 2.68748 Tw 12 TL /F4 10 Tf 0 0 0 rg (signature-preserving ) Tj /F1 10 Tf (decorators, i.e. callable objects taking a function as input and returning a) Tj T* 0 Tw (function ) Tj /F4 10 Tf (with the same signature ) Tj /F1 10 Tf (as output;) Tj T* ET Q Q q Q Q q 1 0 0 1 62.69291 630.0236 cm Q q 1 0 0 1 62.69291 606.0236 cm 0 0 0 rg BT /F1 10 Tf 12 TL ET q 1 0 0 1 6 9 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET Q Q q 1 0 0 1 23 -3 cm q BT 1 0 0 1 0 14 Tm 1.43498 Tw 12 TL /F4 10 Tf 0 0 0 rg (signature-changing ) Tj /F1 10 Tf (decorators, i.e. decorators that change the signature of their input function, or) Tj T* 0 Tw (decorators returning non-callable objects.) Tj T* ET Q Q q Q Q q 1 0 0 1 62.69291 606.0236 cm Q q 1 0 0 1 62.69291 564.0236 cm q BT 1 0 0 1 0 26 Tm 2.832706 Tw 12 TL /F1 10 Tf 0 0 0 rg (Signature-changing decorators have their use: for instance the builtin classes ) Tj /F3 10 Tf 0 0 0 rg (staticmethod ) Tj /F1 10 Tf 0 0 0 rg (and) Tj T* 0 Tw 1.506651 Tw /F3 10 Tf 0 0 0 rg (classmethod ) Tj /F1 10 Tf 0 0 0 rg (are in this group, since they take functions and return descriptor objects which are not) Tj T* 0 Tw (functions, nor callables.) Tj T* ET Q Q q 1 0 0 1 62.69291 534.0236 cm q 0 0 0 rg BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL 1.735814 Tw (However, signature-preserving decorators are more common and easier to reason about; in particular) Tj T* 0 Tw (signature-preserving decorators can be composed together whereas other decorators in general cannot.) Tj T* ET Q Q q 1 0 0 1 62.69291 504.0236 cm q 0 0 0 rg BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .494983 Tw (Writing signature-preserving decorators from scratch is not that obvious, especially if one wants to define) Tj T* 0 Tw (proper decorators that can accept functions with any signature. A simple example will clarify the issue.) Tj T* ET Q Q q 1 0 0 1 62.69291 471.0236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Statement of the problem) Tj T* ET Q Q q 1 0 0 1 62.69291 393.0236 cm q BT 1 0 0 1 0 62 Tm .351235 Tw 12 TL /F1 10 Tf 0 0 0 rg (A very common use case for decorators is the memoization of functions. A ) Tj /F3 10 Tf 0 0 0 rg (memoize ) Tj /F1 10 Tf 0 0 0 rg (decorator works by) Tj T* 0 Tw .871988 Tw (caching the result of the function call in a dictionary, so that the next time the function is called with the) Tj T* 0 Tw 2.350651 Tw (same input parameters the result is retrieved from the cache and not recomputed. There are many) Tj T* 0 Tw 2.92247 Tw (implementations of ) Tj /F3 10 Tf 0 0 0 rg (memoize ) Tj /F1 10 Tf 0 0 0 rg (in ) Tj 0 0 .501961 rg (http://www.python.org/moin/PythonDecoratorLibrary) Tj 0 0 0 rg (, but they do not) Tj T* 0 Tw .692126 Tw (preserve the signature. In recent versions of Python you can find a sophisticated ) Tj /F3 10 Tf 0 0 0 rg (lru_cache ) Tj /F1 10 Tf 0 0 0 rg (decorator) Tj T* 0 Tw (in the standard library \(in ) Tj /F3 10 Tf 0 0 0 rg (functools) Tj /F1 10 Tf 0 0 0 rg (\). Here I am just interested in giving an example.) Tj T* ET Q Q q 1 0 0 1 62.69291 363.0236 cm q 0 0 0 rg BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .017485 Tw (A simple implementation could be the following \(notice that in general it is impossible to memoize correctly) Tj T* 0 Tw (something that depends on non-hashable arguments\):) Tj T* ET Q Q q 1 0 0 1 62.69291 197.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 156 re B* Q q .960784 .960784 .862745 rg n 0 132 18 12 re f* .960784 .960784 .862745 rg n 24 132 60 12 re f* .960784 .960784 .862745 rg n 84 132 6 12 re f* .960784 .960784 .862745 rg n 90 132 24 12 re f* .960784 .960784 .862745 rg n 114 132 12 12 re f* .960784 .960784 .862745 rg n 24 120 24 12 re f* .960784 .960784 .862745 rg n 48 120 6 12 re f* .960784 .960784 .862745 rg n 54 120 30 12 re f* .960784 .960784 .862745 rg n 90 120 6 12 re f* .960784 .960784 .862745 rg n 102 120 12 12 re f* .960784 .960784 .862745 rg n 24 96 18 12 re f* .960784 .960784 .862745 rg n 48 96 42 12 re f* .960784 .960784 .862745 rg n 90 96 6 12 re f* .960784 .960784 .862745 rg n 96 96 6 12 re f* .960784 .960784 .862745 rg n 102 96 24 12 re f* .960784 .960784 .862745 rg n 126 96 6 12 re f* .960784 .960784 .862745 rg n 138 96 12 12 re f* .960784 .960784 .862745 rg n 150 96 12 12 re f* .960784 .960784 .862745 rg n 162 96 12 12 re f* .960784 .960784 .862745 rg n 48 84 12 12 re f* .960784 .960784 .862745 rg n 66 84 12 12 re f* .960784 .960784 .862745 rg n 78 84 6 12 re f* .960784 .960784 .862745 rg n 96 84 246 12 re f* .960784 .960784 .862745 rg n 72 72 18 12 re f* .960784 .960784 .862745 rg n 96 72 6 12 re f* .960784 .960784 .862745 rg n 108 72 24 12 re f* .960784 .960784 .862745 rg n 132 72 6 12 re f* .960784 .960784 .862745 rg n 144 72 54 12 re f* .960784 .960784 .862745 rg n 198 72 6 12 re f* .960784 .960784 .862745 rg n 204 72 12 12 re f* .960784 .960784 .862745 rg n 216 72 6 12 re f* .960784 .960784 .862745 rg n 222 72 30 12 re f* .960784 .960784 .862745 rg n 252 72 18 12 re f* .960784 .960784 .862745 rg n 48 60 24 12 re f* .960784 .960784 .862745 rg n 72 60 6 12 re f* .960784 .960784 .862745 rg n 72 48 18 12 re f* .960784 .960784 .862745 rg n 96 48 6 12 re f* .960784 .960784 .862745 rg n 108 48 24 12 re f* .960784 .960784 .862745 rg n 48 36 12 12 re f* .960784 .960784 .862745 rg n 66 36 18 12 re f* .960784 .960784 .862745 rg n 90 36 18 12 re f* .960784 .960784 .862745 rg n 114 36 12 12 re f* .960784 .960784 .862745 rg n 132 36 24 12 re f* .960784 .960784 .862745 rg n 156 36 6 12 re f* .960784 .960784 .862745 rg n 162 36 30 12 re f* .960784 .960784 .862745 rg n 192 36 6 12 re f* .960784 .960784 .862745 rg n 72 24 24 12 re f* .960784 .960784 .862745 rg n 96 24 6 12 re f* .960784 .960784 .862745 rg n 102 24 30 12 re f* .960784 .960784 .862745 rg n 132 24 6 12 re f* .960784 .960784 .862745 rg n 138 24 18 12 re f* .960784 .960784 .862745 rg n 156 24 6 12 re f* .960784 .960784 .862745 rg n 168 24 6 12 re f* .960784 .960784 .862745 rg n 180 24 24 12 re f* .960784 .960784 .862745 rg n 204 24 6 12 re f* .960784 .960784 .862745 rg n 210 24 6 12 re f* .960784 .960784 .862745 rg n 216 24 24 12 re f* .960784 .960784 .862745 rg n 240 24 6 12 re f* .960784 .960784 .862745 rg n 252 24 12 12 re f* .960784 .960784 .862745 rg n 264 24 12 12 re f* .960784 .960784 .862745 rg n 276 24 6 12 re f* .960784 .960784 .862745 rg n 48 12 36 12 re f* .960784 .960784 .862745 rg n 90 12 24 12 re f* .960784 .960784 .862745 rg n 114 12 6 12 re f* .960784 .960784 .862745 rg n 120 12 30 12 re f* .960784 .960784 .862745 rg n 150 12 6 12 re f* .960784 .960784 .862745 rg n 156 12 18 12 re f* .960784 .960784 .862745 rg n 174 12 6 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 54 12 re f* .960784 .960784 .862745 rg n 120 0 6 12 re f* .960784 .960784 .862745 rg n 126 0 84 12 re f* .960784 .960784 .862745 rg n 210 0 6 12 re f* .960784 .960784 .862745 rg n 216 0 42 12 re f* .960784 .960784 .862745 rg n 258 0 6 12 re f* .960784 .960784 .862745 rg n 270 0 24 12 re f* .960784 .960784 .862745 rg n 294 0 6 12 re f* BT 1 0 0 1 0 134 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (memoize_uw) Tj 0 0 0 rg (\() Tj 0 0 0 rg (func) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (cache) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg ({}) Tj 0 0 0 rg T* T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (memoize) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (if) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (:) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# frozenset is used to ensure hashability) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj 0 0 0 rg (key) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (frozenset) Tj 0 0 0 rg (\() Tj 0 0 0 rg (kw) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (items) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (else) Tj /F3 10 Tf 0 0 0 rg (:) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (key) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (args) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (if) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (key) Tj 0 0 0 rg ( ) Tj /F5 10 Tf .666667 .133333 1 rg (not) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf .666667 .133333 1 rg (in) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (cache) Tj 0 0 0 rg (:) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (cache) Tj 0 0 0 rg ([) Tj 0 0 0 rg (key) Tj 0 0 0 rg (]) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (cache) Tj 0 0 0 rg ([) Tj 0 0 0 rg (key) Tj 0 0 0 rg (]) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (functools) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (update_wrapper) Tj 0 0 0 rg (\() Tj 0 0 0 rg (memoize) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj 0 0 0 rg (\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 141.8236 cm q BT 1 0 0 1 0 38 Tm 2.515697 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here I used the ) Tj 0 0 .501961 rg (functools.update_wrapper ) Tj 0 0 0 rg (utility, which has been added in Python 2.5 expressly to) Tj T* 0 Tw .91686 Tw (simplify the definition of decorators \(in older versions of Python you need to copy the function attributes) Tj T* 0 Tw .580814 Tw /F3 10 Tf 0 0 0 rg (__name__) Tj /F1 10 Tf 0 0 0 rg (, ) Tj /F3 10 Tf 0 0 0 rg (__doc__) Tj /F1 10 Tf 0 0 0 rg (, ) Tj /F3 10 Tf 0 0 0 rg (__module__ ) Tj /F1 10 Tf 0 0 0 rg (and ) Tj /F3 10 Tf 0 0 0 rg (__dict__ ) Tj /F1 10 Tf 0 0 0 rg (from the original function to the decorated function) Tj T* 0 Tw (by hand\). Here is an example of usage:) Tj T* ET Q Q q 1 0 0 1 62.69291 84.62362 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q .960784 .960784 .862745 rg n 0 24 66 12 re f* .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 24 12 12 12 re f* .960784 .960784 .862745 rg n 36 12 6 12 re f* .960784 .960784 .862745 rg n 42 12 6 12 re f* .960784 .960784 .862745 rg n 48 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 192 12 re f* BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf .666667 .133333 1 rg (@memoize_uw) Tj 0 0 0 rg T* /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (f1) Tj 0 0 0 rg (\() Tj 0 0 0 rg (x) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj .729412 .129412 .129412 rg ("Simulate some long computation") Tj 0 0 0 rg T* ET Q Q Q Q Q endstream endobj 107 0 obj << /Length 15279 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 727.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 24 12 24 12 re f* .960784 .960784 .862745 rg n 48 12 6 12 re f* .960784 .960784 .862745 rg n 54 12 30 12 re f* .960784 .960784 .862745 rg n 84 12 6 12 re f* .960784 .960784 .862745 rg n 90 12 6 12 re f* .960784 .960784 .862745 rg n 96 12 6 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 6 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (time) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (sleep) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (x) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 683.8236 cm q BT 1 0 0 1 0 26 Tm 2.517126 Tw 12 TL /F1 10 Tf 0 0 0 rg (The implementation above works in the sense that the decorator can accept functions with generic) Tj T* 0 Tw 1.233615 Tw (signatures; unfortunately this implementation does ) Tj /F4 10 Tf (not ) Tj /F1 10 Tf (define a signature-preserving decorator, since in) Tj T* 0 Tw (general ) Tj /F3 10 Tf 0 0 0 rg (memoize_uw ) Tj /F1 10 Tf 0 0 0 rg (returns a function with a ) Tj /F4 10 Tf (different signature ) Tj /F1 10 Tf (from the original function.) Tj T* ET Q Q q 1 0 0 1 62.69291 665.8236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Consider for instance the following case:) Tj T* ET Q Q q 1 0 0 1 62.69291 584.6236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 72 re B* Q q .960784 .960784 .862745 rg n 0 48 66 12 re f* .960784 .960784 .862745 rg n 0 36 18 12 re f* .960784 .960784 .862745 rg n 24 36 12 12 re f* .960784 .960784 .862745 rg n 36 36 6 12 re f* .960784 .960784 .862745 rg n 42 36 6 12 re f* .960784 .960784 .862745 rg n 48 36 12 12 re f* .960784 .960784 .862745 rg n 24 24 192 12 re f* .960784 .960784 .862745 rg n 24 12 24 12 re f* .960784 .960784 .862745 rg n 48 12 6 12 re f* .960784 .960784 .862745 rg n 54 12 30 12 re f* .960784 .960784 .862745 rg n 84 12 6 12 re f* .960784 .960784 .862745 rg n 90 12 6 12 re f* .960784 .960784 .862745 rg n 96 12 6 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 6 12 re f* BT 1 0 0 1 0 50 Tm 12 TL /F3 10 Tf .666667 .133333 1 rg (@memoize_uw) Tj 0 0 0 rg T* /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (f1) Tj 0 0 0 rg (\() Tj 0 0 0 rg (x) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj .729412 .129412 .129412 rg ("Simulate some long computation") Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (time) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (sleep) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (x) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 552.6236 cm q BT 1 0 0 1 0 14 Tm .26311 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here the original function takes a single argument named ) Tj /F3 10 Tf 0 0 0 rg (x) Tj /F1 10 Tf 0 0 0 rg (, but the decorated function takes any number) Tj T* 0 Tw (of arguments and keyword arguments:) Tj T* ET Q Q q 1 0 0 1 62.69291 495.4236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q .960784 .960784 .862745 rg n 0 24 6 12 re f* .960784 .960784 .862745 rg n 6 24 6 12 re f* .960784 .960784 .862745 rg n 12 24 6 12 re f* .960784 .960784 .862745 rg n 24 24 24 12 re f* .960784 .960784 .862745 rg n 54 24 54 12 re f* .960784 .960784 .862745 rg n 114 24 36 12 re f* .960784 .960784 .862745 rg n 156 24 60 12 re f* .960784 .960784 .862745 rg n 228 24 168 12 re f* .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 30 12 re f* .960784 .960784 .862745 rg n 54 12 6 12 re f* .960784 .960784 .862745 rg n 60 12 60 12 re f* .960784 .960784 .862745 rg n 120 12 6 12 re f* .960784 .960784 .862745 rg n 126 12 12 12 re f* .960784 .960784 .862745 rg n 138 12 12 12 re f* .960784 .960784 .862745 rg n 0 0 42 12 re f* .960784 .960784 .862745 rg n 42 0 6 12 re f* .960784 .960784 .862745 rg n 48 0 24 12 re f* .960784 .960784 .862745 rg n 72 0 6 12 re f* .960784 .960784 .862745 rg n 78 0 18 12 re f* .960784 .960784 .862745 rg n 102 0 42 12 re f* .960784 .960784 .862745 rg n 144 0 6 12 re f* .960784 .960784 .862745 rg n 150 0 36 12 re f* .960784 .960784 .862745 rg n 186 0 6 12 re f* .960784 .960784 .862745 rg n 198 0 30 12 re f* .960784 .960784 .862745 rg n 228 0 6 12 re f* .960784 .960784 .862745 rg n 234 0 24 12 re f* .960784 .960784 .862745 rg n 258 0 6 12 re f* .960784 .960784 .862745 rg n 270 0 48 12 re f* .960784 .960784 .862745 rg n 318 0 6 12 re f* .960784 .960784 .862745 rg n 324 0 24 12 re f* .960784 .960784 .862745 rg n 348 0 6 12 re f* BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (from) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 0 1 rg (decorator) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (import) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (getargspec) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# akin to inspect.getargspec) Tj /F3 10 Tf 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (getargspec) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f1) Tj 0 0 0 rg (\)\)) Tj 0 0 0 rg T* 0 0 0 rg (ArgSpec) Tj 0 0 0 rg (\() Tj 0 0 0 rg (args) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ([],) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (varargs) Tj .4 .4 .4 rg (=) Tj .729412 .129412 .129412 rg ('args') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (varkw) Tj .4 .4 .4 rg (=) Tj .729412 .129412 .129412 rg ('kw') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (defaults) Tj .4 .4 .4 rg (=) Tj 0 .501961 0 rg (None) Tj 0 0 0 rg (\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 439.4236 cm q BT 1 0 0 1 0 38 Tm .002485 Tw 12 TL /F1 10 Tf 0 0 0 rg (This means that introspection tools such as ) Tj /F3 10 Tf 0 0 0 rg (pydoc ) Tj /F1 10 Tf 0 0 0 rg (will give wrong informations about the signature of ) Tj /F3 10 Tf 0 0 0 rg (f1) Tj /F1 10 Tf 0 0 0 rg (,) Tj T* 0 Tw .047356 Tw (unless you are using Python 3.5. This is pretty bad: ) Tj /F3 10 Tf 0 0 0 rg (pydoc ) Tj /F1 10 Tf 0 0 0 rg (will tell you that the function accepts a generic) Tj T* 0 Tw .416303 Tw (signature ) Tj /F3 10 Tf 0 0 0 rg (*args) Tj /F1 10 Tf 0 0 0 rg (, ) Tj /F3 10 Tf 0 0 0 rg (**kw) Tj /F1 10 Tf 0 0 0 rg (, but when you try to call the function with more than an argument, you will get an) Tj T* 0 Tw (error:) Tj T* ET Q Q q 1 0 0 1 62.69291 370.2236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 60 re B* Q q .960784 .960784 .862745 rg n 0 36 6 12 re f* .960784 .960784 .862745 rg n 6 36 6 12 re f* .960784 .960784 .862745 rg n 12 36 6 12 re f* .960784 .960784 .862745 rg n 24 36 12 12 re f* .960784 .960784 .862745 rg n 36 36 6 12 re f* .960784 .960784 .862745 rg n 42 36 6 12 re f* .960784 .960784 .862745 rg n 48 36 6 12 re f* .960784 .960784 .862745 rg n 60 36 6 12 re f* .960784 .960784 .862745 rg n 66 36 6 12 re f* .960784 .960784 .862745 rg n 0 24 54 12 re f* .960784 .960784 .862745 rg n 60 24 6 12 re f* .960784 .960784 .862745 rg n 66 24 24 12 re f* .960784 .960784 .862745 rg n 96 24 36 12 re f* .960784 .960784 .862745 rg n 138 24 24 12 re f* .960784 .960784 .862745 rg n 168 24 24 12 re f* .960784 .960784 .862745 rg n 192 24 12 12 re f* .960784 .960784 .862745 rg n 18 12 18 12 re f* .960784 .960784 .862745 rg n 0 0 54 12 re f* .960784 .960784 .862745 rg n 54 0 6 12 re f* .960784 .960784 .862745 rg n 66 0 12 12 re f* .960784 .960784 .862745 rg n 78 0 12 12 re f* .960784 .960784 .862745 rg n 96 0 30 12 re f* .960784 .960784 .862745 rg n 132 0 42 12 re f* .960784 .960784 .862745 rg n 180 0 6 12 re f* .960784 .960784 .862745 rg n 192 0 60 12 re f* .960784 .960784 .862745 rg n 258 0 48 12 re f* .960784 .960784 .862745 rg n 312 0 6 12 re f* .960784 .960784 .862745 rg n 318 0 6 12 re f* .960784 .960784 .862745 rg n 330 0 30 12 re f* .960784 .960784 .862745 rg n 360 0 6 12 re f* BT 1 0 0 1 0 38 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f1) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (0) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* 0 0 0 rg (Traceback) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (\() Tj 0 0 0 rg (most) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (recent) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (call) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (last) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj .4 .4 .4 rg (...) Tj 0 0 0 rg T* /F5 10 Tf .823529 .254902 .227451 rg (TypeError) Tj /F3 10 Tf 0 0 0 rg (:) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f1) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (takes) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (exactly) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (1) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (positional) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (argument) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (2) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (given) Tj 0 0 0 rg (\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 338.2236 cm q BT 1 0 0 1 0 14 Tm 3.953307 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice even in Python 3.5 ) Tj /F3 10 Tf 0 0 0 rg (inspect.getargspec ) Tj /F1 10 Tf 0 0 0 rg (and ) Tj /F3 10 Tf 0 0 0 rg (inspect.getfullargspec ) Tj /F1 10 Tf 0 0 0 rg (\(which are) Tj T* 0 Tw (deprecated in that release\) will give the wrong signature.) Tj T* ET Q Q q 1 0 0 1 62.69291 305.2236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (The solution) Tj T* ET Q Q q 1 0 0 1 62.69291 263.2236 cm q BT 1 0 0 1 0 26 Tm 3.313984 Tw 12 TL /F1 10 Tf 0 0 0 rg (The solution is to provide a generic factory of generators, which hides the complexity of making) Tj T* 0 Tw 3.962976 Tw (signature-preserving decorators from the application programmer. The ) Tj /F3 10 Tf 0 0 0 rg (decorate ) Tj /F1 10 Tf 0 0 0 rg (function in the) Tj T* 0 Tw /F3 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf 0 0 0 rg (module is such a factory:) Tj T* ET Q Q q 1 0 0 1 62.69291 230.0236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 24 re B* Q q .960784 .960784 .862745 rg n 0 0 6 12 re f* .960784 .960784 .862745 rg n 6 0 6 12 re f* .960784 .960784 .862745 rg n 12 0 6 12 re f* .960784 .960784 .862745 rg n 24 0 24 12 re f* .960784 .960784 .862745 rg n 54 0 54 12 re f* .960784 .960784 .862745 rg n 114 0 36 12 re f* .960784 .960784 .862745 rg n 156 0 48 12 re f* BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (from) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 0 1 rg (decorator) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (import) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (decorate) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 174.0236 cm q BT 1 0 0 1 0 38 Tm 2.144983 Tw 12 TL /F3 10 Tf 0 0 0 rg (decorate ) Tj /F1 10 Tf 0 0 0 rg (takes two arguments, a caller function describing the functionality of the decorator and a) Tj T* 0 Tw 2.594983 Tw (function to be decorated; it returns the decorated function. The caller function must have signature) Tj T* 0 Tw .19311 Tw /F3 10 Tf 0 0 0 rg (\(f,) Tj ( ) Tj (*args,) Tj ( ) Tj (**kw\) ) Tj /F1 10 Tf 0 0 0 rg (and it must call the original function ) Tj /F3 10 Tf 0 0 0 rg (f ) Tj /F1 10 Tf 0 0 0 rg (with arguments ) Tj /F3 10 Tf 0 0 0 rg (args ) Tj /F1 10 Tf 0 0 0 rg (and ) Tj /F3 10 Tf 0 0 0 rg (kw) Tj /F1 10 Tf 0 0 0 rg (, implementing) Tj T* 0 Tw (the wanted capability, i.e. memoization in this case:) Tj T* ET Q Q q 1 0 0 1 62.69291 80.82362 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 84 re B* Q q .960784 .960784 .862745 rg n 0 60 18 12 re f* .960784 .960784 .862745 rg n 24 60 48 12 re f* .960784 .960784 .862745 rg n 72 60 6 12 re f* .960784 .960784 .862745 rg n 78 60 24 12 re f* .960784 .960784 .862745 rg n 102 60 6 12 re f* .960784 .960784 .862745 rg n 114 60 6 12 re f* .960784 .960784 .862745 rg n 120 60 24 12 re f* .960784 .960784 .862745 rg n 144 60 6 12 re f* .960784 .960784 .862745 rg n 156 60 12 12 re f* .960784 .960784 .862745 rg n 168 60 12 12 re f* .960784 .960784 .862745 rg n 180 60 12 12 re f* .960784 .960784 .862745 rg n 24 48 12 12 re f* .960784 .960784 .862745 rg n 42 48 12 12 re f* .960784 .960784 .862745 rg n 54 48 6 12 re f* .960784 .960784 .862745 rg n 72 48 246 12 re f* .960784 .960784 .862745 rg n 48 36 18 12 re f* .960784 .960784 .862745 rg n 72 36 6 12 re f* .960784 .960784 .862745 rg n 84 36 24 12 re f* .960784 .960784 .862745 rg n 108 36 6 12 re f* .960784 .960784 .862745 rg n 120 36 54 12 re f* .960784 .960784 .862745 rg n 174 36 6 12 re f* .960784 .960784 .862745 rg n 180 36 12 12 re f* .960784 .960784 .862745 rg n 192 36 6 12 re f* .960784 .960784 .862745 rg n 198 36 30 12 re f* .960784 .960784 .862745 rg n 228 36 18 12 re f* .960784 .960784 .862745 rg n 24 24 24 12 re f* .960784 .960784 .862745 rg n 48 24 6 12 re f* .960784 .960784 .862745 rg n 48 12 18 12 re f* .960784 .960784 .862745 rg n 72 12 6 12 re f* .960784 .960784 .862745 rg n 84 12 24 12 re f* .960784 .960784 .862745 rg n 24 0 30 12 re f* .960784 .960784 .862745 rg n 60 0 6 12 re f* .960784 .960784 .862745 rg n 72 0 24 12 re f* .960784 .960784 .862745 rg n 96 0 6 12 re f* .960784 .960784 .862745 rg n 102 0 30 12 re f* .960784 .960784 .862745 rg n 144 0 168 12 re f* BT 1 0 0 1 0 62 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (_memoize) Tj 0 0 0 rg (\() Tj 0 0 0 rg (func) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (if) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (:) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# frozenset is used to ensure hashability) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj 0 0 0 rg (key) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (frozenset) Tj 0 0 0 rg (\() Tj 0 0 0 rg (kw) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (items) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (else) Tj /F3 10 Tf 0 0 0 rg (:) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (key) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (args) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (cache) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (cache) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# attribute added by memoize) Tj /F3 10 Tf 0 0 0 rg T* ET Q Q Q Q Q endstream endobj 108 0 obj << /Length 17710 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 715.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q .960784 .960784 .862745 rg n 24 24 12 12 re f* .960784 .960784 .862745 rg n 42 24 18 12 re f* .960784 .960784 .862745 rg n 66 24 18 12 re f* .960784 .960784 .862745 rg n 90 24 12 12 re f* .960784 .960784 .862745 rg n 108 24 30 12 re f* .960784 .960784 .862745 rg n 138 24 6 12 re f* .960784 .960784 .862745 rg n 48 12 30 12 re f* .960784 .960784 .862745 rg n 78 12 6 12 re f* .960784 .960784 .862745 rg n 84 12 18 12 re f* .960784 .960784 .862745 rg n 102 12 6 12 re f* .960784 .960784 .862745 rg n 114 12 6 12 re f* .960784 .960784 .862745 rg n 126 12 24 12 re f* .960784 .960784 .862745 rg n 150 12 6 12 re f* .960784 .960784 .862745 rg n 156 12 6 12 re f* .960784 .960784 .862745 rg n 162 12 24 12 re f* .960784 .960784 .862745 rg n 186 12 6 12 re f* .960784 .960784 .862745 rg n 198 12 12 12 re f* .960784 .960784 .862745 rg n 210 12 12 12 re f* .960784 .960784 .862745 rg n 222 12 6 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 30 12 re f* .960784 .960784 .862745 rg n 96 0 6 12 re f* .960784 .960784 .862745 rg n 102 0 18 12 re f* .960784 .960784 .862745 rg n 120 0 6 12 re f* BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (if) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (key) Tj 0 0 0 rg ( ) Tj /F5 10 Tf .666667 .133333 1 rg (not) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf .666667 .133333 1 rg (in) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (cache) Tj 0 0 0 rg (:) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (cache) Tj 0 0 0 rg ([) Tj 0 0 0 rg (key) Tj 0 0 0 rg (]) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (cache) Tj 0 0 0 rg ([) Tj 0 0 0 rg (key) Tj 0 0 0 rg (]) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 695.8236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (At this point you can define your decorator as follows:) Tj T* ET Q Q q 1 0 0 1 62.69291 578.6236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 108 re B* Q q .960784 .960784 .862745 rg n 0 84 18 12 re f* .960784 .960784 .862745 rg n 24 84 42 12 re f* .960784 .960784 .862745 rg n 66 84 6 12 re f* .960784 .960784 .862745 rg n 72 84 6 12 re f* .960784 .960784 .862745 rg n 78 84 12 12 re f* .960784 .960784 .862745 rg n 24 72 18 12 re f* .960784 .960784 .862745 rg n 0 60 450 12 re f* .960784 .960784 .862745 rg n 0 48 438 12 re f* .960784 .960784 .862745 rg n 0 36 282 12 re f* .960784 .960784 .862745 rg n 0 24 42 12 re f* .960784 .960784 .862745 rg n 24 12 6 12 re f* .960784 .960784 .862745 rg n 30 12 6 12 re f* .960784 .960784 .862745 rg n 36 12 30 12 re f* .960784 .960784 .862745 rg n 72 12 6 12 re f* .960784 .960784 .862745 rg n 84 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 48 12 re f* .960784 .960784 .862745 rg n 114 0 6 12 re f* .960784 .960784 .862745 rg n 120 0 6 12 re f* .960784 .960784 .862745 rg n 126 0 6 12 re f* .960784 .960784 .862745 rg n 138 0 48 12 re f* .960784 .960784 .862745 rg n 186 0 6 12 re f* BT 1 0 0 1 0 86 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (memoize) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf .729412 .129412 .129412 rg (""") Tj T* ( A simple memoize implementation. It works by adding a .cache dictionary) Tj T* ( to the decorated function. The cache will grow indefinitely, so it is) Tj T* ( your responsability to clear it, if needed.) Tj T* ( """) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj 0 0 0 rg (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (cache) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg ({}) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (decorate) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (_memoize) Tj 0 0 0 rg (\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 534.6236 cm q BT 1 0 0 1 0 26 Tm .12561 Tw 12 TL /F1 10 Tf 0 0 0 rg (The difference with respect to the ) Tj /F3 10 Tf 0 0 0 rg (memoize_uw ) Tj /F1 10 Tf 0 0 0 rg (approach, which is based on nested functions, is that the) Tj T* 0 Tw .598876 Tw (decorator module forces you to lift the inner function at the outer level. Moreover, you are forced to pass) Tj T* 0 Tw (explicitly the function you want to decorate, there are no closures.) Tj T* ET Q Q q 1 0 0 1 62.69291 516.6236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Here is a test of usage:) Tj T* ET Q Q q 1 0 0 1 62.69291 375.4236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 132 re B* Q q .960784 .960784 .862745 rg n 0 108 6 12 re f* .960784 .960784 .862745 rg n 6 108 6 12 re f* .960784 .960784 .862745 rg n 12 108 6 12 re f* .960784 .960784 .862745 rg n 24 108 48 12 re f* .960784 .960784 .862745 rg n 0 96 18 12 re f* .960784 .960784 .862745 rg n 24 96 18 12 re f* .960784 .960784 .862745 rg n 48 96 102 12 re f* .960784 .960784 .862745 rg n 150 96 18 12 re f* .960784 .960784 .862745 rg n 0 84 18 12 re f* .960784 .960784 .862745 rg n 48 84 24 12 re f* .960784 .960784 .862745 rg n 72 84 6 12 re f* .960784 .960784 .862745 rg n 78 84 30 12 re f* .960784 .960784 .862745 rg n 108 84 6 12 re f* .960784 .960784 .862745 rg n 114 84 6 12 re f* .960784 .960784 .862745 rg n 120 84 6 12 re f* .960784 .960784 .862745 rg n 0 72 18 12 re f* .960784 .960784 .862745 rg n 48 72 36 12 re f* .960784 .960784 .862745 rg n 90 72 36 12 re f* .960784 .960784 .862745 rg n 0 48 6 12 re f* .960784 .960784 .862745 rg n 6 48 6 12 re f* .960784 .960784 .862745 rg n 12 48 6 12 re f* .960784 .960784 .862745 rg n 24 48 30 12 re f* .960784 .960784 .862745 rg n 54 48 6 12 re f* .960784 .960784 .862745 rg n 60 48 102 12 re f* .960784 .960784 .862745 rg n 162 48 18 12 re f* .960784 .960784 .862745 rg n 186 48 234 12 re f* .960784 .960784 .862745 rg n 0 36 24 12 re f* .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 30 12 re f* .960784 .960784 .862745 rg n 54 12 6 12 re f* .960784 .960784 .862745 rg n 60 12 102 12 re f* .960784 .960784 .862745 rg n 162 12 18 12 re f* .960784 .960784 .862745 rg n 186 12 252 12 re f* .960784 .960784 .862745 rg n 0 0 24 12 re f* BT 1 0 0 1 0 110 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj .666667 .133333 1 rg (@memoize) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (heavy_computation) Tj 0 0 0 rg (\(\):) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (time) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (sleep) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("done") Tj 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (heavy_computation) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# the first time it will take 2 seconds) Tj /F3 10 Tf 0 0 0 rg T* 0 0 0 rg (done) Tj 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (heavy_computation) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# the second time it will be instantaneous) Tj /F3 10 Tf 0 0 0 rg T* 0 0 0 rg (done) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 355.4236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (The signature of ) Tj /F3 10 Tf 0 0 0 rg (heavy_computation ) Tj /F1 10 Tf 0 0 0 rg (is the one you would expect:) Tj T* ET Q Q q 1 0 0 1 62.69291 310.2236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 30 12 re f* .960784 .960784 .862745 rg n 54 12 6 12 re f* .960784 .960784 .862745 rg n 60 12 60 12 re f* .960784 .960784 .862745 rg n 120 12 6 12 re f* .960784 .960784 .862745 rg n 126 12 102 12 re f* .960784 .960784 .862745 rg n 228 12 12 12 re f* .960784 .960784 .862745 rg n 0 0 42 12 re f* .960784 .960784 .862745 rg n 42 0 6 12 re f* .960784 .960784 .862745 rg n 48 0 24 12 re f* .960784 .960784 .862745 rg n 72 0 6 12 re f* .960784 .960784 .862745 rg n 78 0 18 12 re f* .960784 .960784 .862745 rg n 102 0 42 12 re f* .960784 .960784 .862745 rg n 144 0 6 12 re f* .960784 .960784 .862745 rg n 150 0 24 12 re f* .960784 .960784 .862745 rg n 174 0 6 12 re f* .960784 .960784 .862745 rg n 186 0 30 12 re f* .960784 .960784 .862745 rg n 216 0 6 12 re f* .960784 .960784 .862745 rg n 222 0 24 12 re f* .960784 .960784 .862745 rg n 246 0 6 12 re f* .960784 .960784 .862745 rg n 258 0 48 12 re f* .960784 .960784 .862745 rg n 306 0 6 12 re f* .960784 .960784 .862745 rg n 312 0 24 12 re f* .960784 .960784 .862745 rg n 336 0 6 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (getargspec) Tj 0 0 0 rg (\() Tj 0 0 0 rg (heavy_computation) Tj 0 0 0 rg (\)\)) Tj 0 0 0 rg T* 0 0 0 rg (ArgSpec) Tj 0 0 0 rg (\() Tj 0 0 0 rg (args) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ([],) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (varargs) Tj .4 .4 .4 rg (=) Tj 0 .501961 0 rg (None) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (varkw) Tj .4 .4 .4 rg (=) Tj 0 .501961 0 rg (None) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (defaults) Tj .4 .4 .4 rg (=) Tj 0 .501961 0 rg (None) Tj 0 0 0 rg (\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 277.2236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (A ) Tj /F3 17.5 Tf 0 0 0 rg (trace ) Tj /F2 17.5 Tf 0 0 0 rg (decorator) Tj T* ET Q Q q 1 0 0 1 62.69291 247.2236 cm q BT 1 0 0 1 0 14 Tm .479398 Tw 12 TL /F1 10 Tf 0 0 0 rg (As an additional example, here is how you can define a trivial ) Tj /F3 10 Tf 0 0 0 rg (trace ) Tj /F1 10 Tf 0 0 0 rg (decorator, which prints a message) Tj T* 0 Tw (everytime the traced function is called:) Tj T* ET Q Q q 1 0 0 1 62.69291 178.0236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 60 re B* Q q .960784 .960784 .862745 rg n 0 36 18 12 re f* .960784 .960784 .862745 rg n 24 36 36 12 re f* .960784 .960784 .862745 rg n 60 36 6 12 re f* .960784 .960784 .862745 rg n 66 36 6 12 re f* .960784 .960784 .862745 rg n 72 36 6 12 re f* .960784 .960784 .862745 rg n 84 36 6 12 re f* .960784 .960784 .862745 rg n 90 36 24 12 re f* .960784 .960784 .862745 rg n 114 36 6 12 re f* .960784 .960784 .862745 rg n 126 36 12 12 re f* .960784 .960784 .862745 rg n 138 36 12 12 re f* .960784 .960784 .862745 rg n 150 36 12 12 re f* .960784 .960784 .862745 rg n 24 24 30 12 re f* .960784 .960784 .862745 rg n 60 24 6 12 re f* .960784 .960784 .862745 rg n 72 24 24 12 re f* .960784 .960784 .862745 rg n 96 24 6 12 re f* .960784 .960784 .862745 rg n 102 24 24 12 re f* .960784 .960784 .862745 rg n 126 24 6 12 re f* .960784 .960784 .862745 rg n 132 24 6 12 re f* .960784 .960784 .862745 rg n 138 24 12 12 re f* .960784 .960784 .862745 rg n 150 24 6 12 re f* .960784 .960784 .862745 rg n 162 24 12 12 re f* .960784 .960784 .862745 rg n 174 24 6 12 re f* .960784 .960784 .862745 rg n 186 24 6 12 re f* .960784 .960784 .862745 rg n 198 24 6 12 re f* .960784 .960784 .862745 rg n 204 24 6 12 re f* .960784 .960784 .862745 rg n 210 24 6 12 re f* .960784 .960784 .862745 rg n 222 24 12 12 re f* .960784 .960784 .862745 rg n 234 24 6 12 re f* .960784 .960784 .862745 rg n 240 24 6 12 re f* .960784 .960784 .862745 rg n 246 24 12 12 re f* .960784 .960784 .862745 rg n 264 24 18 12 re f* .960784 .960784 .862745 rg n 288 24 6 12 re f* .960784 .960784 .862745 rg n 300 24 12 12 re f* .960784 .960784 .862745 rg n 318 24 36 12 re f* .960784 .960784 .862745 rg n 354 24 6 12 re f* .960784 .960784 .862745 rg n 360 24 12 12 re f* .960784 .960784 .862745 rg n 372 24 12 12 re f* .960784 .960784 .862745 rg n 24 12 30 12 re f* .960784 .960784 .862745 rg n 54 12 6 12 re f* .960784 .960784 .862745 rg n 60 12 48 12 re f* .960784 .960784 .862745 rg n 114 12 12 12 re f* .960784 .960784 .862745 rg n 126 12 60 12 re f* .960784 .960784 .862745 rg n 192 12 12 12 re f* .960784 .960784 .862745 rg n 204 12 18 12 re f* .960784 .960784 .862745 rg n 222 12 12 12 re f* .960784 .960784 .862745 rg n 234 12 12 12 re f* .960784 .960784 .862745 rg n 252 12 6 12 re f* .960784 .960784 .862745 rg n 264 12 6 12 re f* .960784 .960784 .862745 rg n 270 12 6 12 re f* .960784 .960784 .862745 rg n 276 12 6 12 re f* .960784 .960784 .862745 rg n 282 12 48 12 re f* .960784 .960784 .862745 rg n 330 12 6 12 re f* .960784 .960784 .862745 rg n 342 12 24 12 re f* .960784 .960784 .862745 rg n 366 12 6 12 re f* .960784 .960784 .862745 rg n 378 12 30 12 re f* .960784 .960784 .862745 rg n 408 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 6 12 re f* .960784 .960784 .862745 rg n 72 0 6 12 re f* .960784 .960784 .862745 rg n 78 0 6 12 re f* .960784 .960784 .862745 rg n 84 0 24 12 re f* .960784 .960784 .862745 rg n 108 0 6 12 re f* .960784 .960784 .862745 rg n 120 0 12 12 re f* .960784 .960784 .862745 rg n 132 0 12 12 re f* .960784 .960784 .862745 rg n 144 0 6 12 re f* BT 1 0 0 1 0 38 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (_trace) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (kwstr) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg (', ') Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (join) Tj 0 0 0 rg (\() Tj .729412 .129412 .129412 rg (') Tj /F5 10 Tf .733333 .4 .533333 rg (%r) Tj /F3 10 Tf .729412 .129412 .129412 rg (: ) Tj /F5 10 Tf .733333 .4 .533333 rg (%r) Tj /F3 10 Tf .729412 .129412 .129412 rg (') Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (%) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (\() Tj 0 0 0 rg (k) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (kw) Tj 0 0 0 rg ([) Tj 0 0 0 rg (k) Tj 0 0 0 rg (]\)) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (for) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (k) Tj 0 0 0 rg ( ) Tj /F5 10 Tf .666667 .133333 1 rg (in) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (sorted) Tj 0 0 0 rg (\() Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\)\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ("calling ) Tj /F5 10 Tf .733333 .4 .533333 rg (%s) Tj /F3 10 Tf .729412 .129412 .129412 rg ( with args ) Tj /F5 10 Tf .733333 .4 .533333 rg (%s) Tj /F3 10 Tf .729412 .129412 .129412 rg (, {) Tj /F5 10 Tf .733333 .4 .533333 rg (%s) Tj /F3 10 Tf .729412 .129412 .129412 rg (}") Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (%) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__name__) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (kwstr) Tj 0 0 0 rg (\)\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (f) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 132.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 24 12 30 12 re f* .960784 .960784 .862745 rg n 54 12 6 12 re f* .960784 .960784 .862745 rg n 60 12 6 12 re f* .960784 .960784 .862745 rg n 66 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 48 12 re f* .960784 .960784 .862745 rg n 114 0 6 12 re f* .960784 .960784 .862745 rg n 120 0 6 12 re f* .960784 .960784 .862745 rg n 126 0 6 12 re f* .960784 .960784 .862745 rg n 138 0 36 12 re f* .960784 .960784 .862745 rg n 174 0 6 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (trace) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (decorate) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (_trace) Tj 0 0 0 rg (\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 112.8236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Here is an example of usage:) Tj T* ET Q Q endstream endobj 109 0 obj << /Length 20286 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 715.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q .960784 .960784 .862745 rg n 0 24 6 12 re f* .960784 .960784 .862745 rg n 6 24 6 12 re f* .960784 .960784 .862745 rg n 12 24 6 12 re f* .960784 .960784 .862745 rg n 24 24 36 12 re f* .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 24 12 18 12 re f* .960784 .960784 .862745 rg n 48 12 12 12 re f* .960784 .960784 .862745 rg n 60 12 6 12 re f* .960784 .960784 .862745 rg n 66 12 6 12 re f* .960784 .960784 .862745 rg n 72 12 12 12 re f* .960784 .960784 .862745 rg n 0 0 18 12 re f* .960784 .960784 .862745 rg n 48 0 24 12 re f* BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj .666667 .133333 1 rg (@trace) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (f1) Tj 0 0 0 rg (\() Tj 0 0 0 rg (x) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (pass) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 695.8236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (It is immediate to verify that ) Tj /F3 10 Tf 0 0 0 rg (f1 ) Tj /F1 10 Tf 0 0 0 rg (works) Tj T* ET Q Q q 1 0 0 1 62.69291 650.6236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 12 12 re f* .960784 .960784 .862745 rg n 36 12 6 12 re f* .960784 .960784 .862745 rg n 42 12 6 12 re f* .960784 .960784 .862745 rg n 48 12 6 12 re f* .960784 .960784 .862745 rg n 0 0 42 12 re f* .960784 .960784 .862745 rg n 48 0 12 12 re f* .960784 .960784 .862745 rg n 66 0 24 12 re f* .960784 .960784 .862745 rg n 96 0 24 12 re f* .960784 .960784 .862745 rg n 126 0 6 12 re f* .960784 .960784 .862745 rg n 132 0 6 12 re f* .960784 .960784 .862745 rg n 138 0 18 12 re f* .960784 .960784 .862745 rg n 162 0 12 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f1) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (0) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* 0 0 0 rg (calling) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f1) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (with) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (args) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (0) Tj 0 0 0 rg (,\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg ({}) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 630.6236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (and it that it has the correct signature:) Tj T* ET Q Q q 1 0 0 1 62.69291 585.4236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 30 12 re f* .960784 .960784 .862745 rg n 54 12 6 12 re f* .960784 .960784 .862745 rg n 60 12 60 12 re f* .960784 .960784 .862745 rg n 120 12 6 12 re f* .960784 .960784 .862745 rg n 126 12 12 12 re f* .960784 .960784 .862745 rg n 138 12 12 12 re f* .960784 .960784 .862745 rg n 0 0 42 12 re f* .960784 .960784 .862745 rg n 42 0 6 12 re f* .960784 .960784 .862745 rg n 48 0 24 12 re f* .960784 .960784 .862745 rg n 72 0 6 12 re f* .960784 .960784 .862745 rg n 78 0 6 12 re f* .960784 .960784 .862745 rg n 84 0 18 12 re f* .960784 .960784 .862745 rg n 102 0 12 12 re f* .960784 .960784 .862745 rg n 120 0 42 12 re f* .960784 .960784 .862745 rg n 162 0 6 12 re f* .960784 .960784 .862745 rg n 168 0 24 12 re f* .960784 .960784 .862745 rg n 192 0 6 12 re f* .960784 .960784 .862745 rg n 204 0 30 12 re f* .960784 .960784 .862745 rg n 234 0 6 12 re f* .960784 .960784 .862745 rg n 240 0 24 12 re f* .960784 .960784 .862745 rg n 264 0 6 12 re f* .960784 .960784 .862745 rg n 276 0 48 12 re f* .960784 .960784 .862745 rg n 324 0 6 12 re f* .960784 .960784 .862745 rg n 330 0 24 12 re f* .960784 .960784 .862745 rg n 354 0 6 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (getargspec) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f1) Tj 0 0 0 rg (\)\)) Tj 0 0 0 rg T* 0 0 0 rg (ArgSpec) Tj 0 0 0 rg (\() Tj 0 0 0 rg (args) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ([) Tj .729412 .129412 .129412 rg ('x') Tj 0 0 0 rg (],) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (varargs) Tj .4 .4 .4 rg (=) Tj 0 .501961 0 rg (None) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (varkw) Tj .4 .4 .4 rg (=) Tj 0 .501961 0 rg (None) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (defaults) Tj .4 .4 .4 rg (=) Tj 0 .501961 0 rg (None) Tj 0 0 0 rg (\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 565.4236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (The same decorator works with functions of any signature:) Tj T* ET Q Q q 1 0 0 1 62.69291 436.2236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 120 re B* Q q .960784 .960784 .862745 rg n 0 96 6 12 re f* .960784 .960784 .862745 rg n 6 96 6 12 re f* .960784 .960784 .862745 rg n 12 96 6 12 re f* .960784 .960784 .862745 rg n 24 96 36 12 re f* .960784 .960784 .862745 rg n 0 84 18 12 re f* .960784 .960784 .862745 rg n 24 84 18 12 re f* .960784 .960784 .862745 rg n 48 84 6 12 re f* .960784 .960784 .862745 rg n 54 84 6 12 re f* .960784 .960784 .862745 rg n 60 84 6 12 re f* .960784 .960784 .862745 rg n 66 84 6 12 re f* .960784 .960784 .862745 rg n 78 84 6 12 re f* .960784 .960784 .862745 rg n 84 84 6 12 re f* .960784 .960784 .862745 rg n 90 84 6 12 re f* .960784 .960784 .862745 rg n 96 84 6 12 re f* .960784 .960784 .862745 rg n 108 84 6 12 re f* .960784 .960784 .862745 rg n 114 84 6 12 re f* .960784 .960784 .862745 rg n 120 84 6 12 re f* .960784 .960784 .862745 rg n 126 84 6 12 re f* .960784 .960784 .862745 rg n 138 84 6 12 re f* .960784 .960784 .862745 rg n 144 84 24 12 re f* .960784 .960784 .862745 rg n 168 84 6 12 re f* .960784 .960784 .862745 rg n 180 84 12 12 re f* .960784 .960784 .862745 rg n 192 84 12 12 re f* .960784 .960784 .862745 rg n 204 84 12 12 re f* .960784 .960784 .862745 rg n 0 72 18 12 re f* .960784 .960784 .862745 rg n 48 72 24 12 re f* .960784 .960784 .862745 rg n 0 48 6 12 re f* .960784 .960784 .862745 rg n 6 48 6 12 re f* .960784 .960784 .862745 rg n 12 48 6 12 re f* .960784 .960784 .862745 rg n 24 48 6 12 re f* .960784 .960784 .862745 rg n 30 48 6 12 re f* .960784 .960784 .862745 rg n 36 48 6 12 re f* .960784 .960784 .862745 rg n 42 48 6 12 re f* .960784 .960784 .862745 rg n 54 48 6 12 re f* .960784 .960784 .862745 rg n 60 48 6 12 re f* .960784 .960784 .862745 rg n 0 36 42 12 re f* .960784 .960784 .862745 rg n 48 36 6 12 re f* .960784 .960784 .862745 rg n 60 36 24 12 re f* .960784 .960784 .862745 rg n 90 36 24 12 re f* .960784 .960784 .862745 rg n 120 36 6 12 re f* .960784 .960784 .862745 rg n 126 36 6 12 re f* .960784 .960784 .862745 rg n 132 36 6 12 re f* .960784 .960784 .862745 rg n 144 36 6 12 re f* .960784 .960784 .862745 rg n 150 36 6 12 re f* .960784 .960784 .862745 rg n 162 36 6 12 re f* .960784 .960784 .862745 rg n 168 36 12 12 re f* .960784 .960784 .862745 rg n 186 36 12 12 re f* .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 30 12 re f* .960784 .960784 .862745 rg n 54 12 6 12 re f* .960784 .960784 .862745 rg n 60 12 60 12 re f* .960784 .960784 .862745 rg n 120 12 6 12 re f* .960784 .960784 .862745 rg n 126 12 6 12 re f* .960784 .960784 .862745 rg n 132 12 12 12 re f* .960784 .960784 .862745 rg n 0 0 42 12 re f* .960784 .960784 .862745 rg n 42 0 6 12 re f* .960784 .960784 .862745 rg n 48 0 24 12 re f* .960784 .960784 .862745 rg n 72 0 6 12 re f* .960784 .960784 .862745 rg n 78 0 6 12 re f* .960784 .960784 .862745 rg n 84 0 18 12 re f* .960784 .960784 .862745 rg n 102 0 6 12 re f* .960784 .960784 .862745 rg n 114 0 18 12 re f* .960784 .960784 .862745 rg n 132 0 6 12 re f* .960784 .960784 .862745 rg n 144 0 18 12 re f* .960784 .960784 .862745 rg n 162 0 12 12 re f* .960784 .960784 .862745 rg n 180 0 42 12 re f* .960784 .960784 .862745 rg n 222 0 6 12 re f* .960784 .960784 .862745 rg n 228 0 36 12 re f* .960784 .960784 .862745 rg n 264 0 6 12 re f* .960784 .960784 .862745 rg n 276 0 30 12 re f* .960784 .960784 .862745 rg n 306 0 6 12 re f* .960784 .960784 .862745 rg n 312 0 24 12 re f* .960784 .960784 .862745 rg n 336 0 6 12 re f* .960784 .960784 .862745 rg n 348 0 48 12 re f* .960784 .960784 .862745 rg n 396 0 6 12 re f* .960784 .960784 .862745 rg n 402 0 6 12 re f* .960784 .960784 .862745 rg n 408 0 6 12 re f* .960784 .960784 .862745 rg n 414 0 6 12 re f* .960784 .960784 .862745 rg n 426 0 6 12 re f* .960784 .960784 .862745 rg n 432 0 12 12 re f* BT 1 0 0 1 0 98 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj .666667 .133333 1 rg (@trace) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (f) Tj 0 0 0 rg (\() Tj 0 0 0 rg (x) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (y) Tj .4 .4 .4 rg (=) Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (z) Tj .4 .4 .4 rg (=) Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (pass) Tj /F3 10 Tf 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (0) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (3) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* 0 0 0 rg (calling) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (with) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (args) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (0) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (3) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg ({}) Tj 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (getargspec) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f) Tj 0 0 0 rg (\)\)) Tj 0 0 0 rg T* 0 0 0 rg (ArgSpec) Tj 0 0 0 rg (\() Tj 0 0 0 rg (args) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ([) Tj .729412 .129412 .129412 rg ('x') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('y') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('z') Tj 0 0 0 rg (],) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (varargs) Tj .4 .4 .4 rg (=) Tj .729412 .129412 .129412 rg ('args') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (varkw) Tj .4 .4 .4 rg (=) Tj .729412 .129412 .129412 rg ('kw') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (defaults) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (\)\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 403.2236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Function annotations) Tj T* ET Q Q q 1 0 0 1 62.69291 349.2236 cm q BT 1 0 0 1 0 38 Tm 1.937318 Tw 12 TL /F1 10 Tf 0 0 0 rg (Python 3 introduced the concept of ) Tj 0 0 .501961 rg (function annotations) Tj 0 0 0 rg (,i.e. the ability to annotate the signature of a) Tj T* 0 Tw 2.24816 Tw (function with additional information, stored in a dictionary named ) Tj /F3 10 Tf 0 0 0 rg (__annotations__) Tj /F1 10 Tf 0 0 0 rg (. The decorator) Tj T* 0 Tw 1.923735 Tw (module, starting from release 3.3, is able to understand and to preserve the annotations. Here is an) Tj T* 0 Tw (example:) Tj T* ET Q Q q 1 0 0 1 62.69291 280.0236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 60 re B* Q q .960784 .960784 .862745 rg n 0 36 6 12 re f* .960784 .960784 .862745 rg n 6 36 6 12 re f* .960784 .960784 .862745 rg n 12 36 6 12 re f* .960784 .960784 .862745 rg n 24 36 36 12 re f* .960784 .960784 .862745 rg n 0 24 18 12 re f* .960784 .960784 .862745 rg n 24 24 18 12 re f* .960784 .960784 .862745 rg n 48 24 6 12 re f* .960784 .960784 .862745 rg n 54 24 6 12 re f* .960784 .960784 .862745 rg n 60 24 6 12 re f* .960784 .960784 .862745 rg n 66 24 6 12 re f* .960784 .960784 .862745 rg n 78 24 120 12 re f* .960784 .960784 .862745 rg n 198 24 6 12 re f* .960784 .960784 .862745 rg n 210 24 6 12 re f* .960784 .960784 .862745 rg n 216 24 6 12 re f* .960784 .960784 .862745 rg n 228 24 108 12 re f* .960784 .960784 .862745 rg n 336 24 6 12 re f* .960784 .960784 .862745 rg n 342 24 6 12 re f* .960784 .960784 .862745 rg n 348 24 6 12 re f* .960784 .960784 .862745 rg n 360 24 6 12 re f* .960784 .960784 .862745 rg n 366 24 6 12 re f* .960784 .960784 .862745 rg n 372 24 6 12 re f* .960784 .960784 .862745 rg n 378 24 6 12 re f* .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 60 12 6 12 re f* .960784 .960784 .862745 rg n 66 12 24 12 re f* .960784 .960784 .862745 rg n 90 12 6 12 re f* .960784 .960784 .862745 rg n 102 12 54 12 re f* .960784 .960784 .862745 rg n 156 12 6 12 re f* .960784 .960784 .862745 rg n 168 12 12 12 re f* .960784 .960784 .862745 rg n 180 12 12 12 re f* .960784 .960784 .862745 rg n 192 12 6 12 re f* .960784 .960784 .862745 rg n 204 12 48 12 re f* .960784 .960784 .862745 rg n 252 12 12 12 re f* .960784 .960784 .862745 rg n 0 0 18 12 re f* .960784 .960784 .862745 rg n 48 0 24 12 re f* BT 1 0 0 1 0 38 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj .666667 .133333 1 rg (@trace) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (f) Tj 0 0 0 rg (\() Tj 0 0 0 rg (x) Tj 0 0 0 rg (:) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('the first argument') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (y) Tj 0 0 0 rg (:) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('default argument') Tj .4 .4 .4 rg (=) Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (z) Tj .4 .4 .4 rg (=) Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (,) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (:) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('varargs') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (:) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('kwargs') Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (pass) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 248.0236 cm q BT 1 0 0 1 0 14 Tm .596647 Tw 12 TL /F1 10 Tf 0 0 0 rg (In order to introspect functions with annotations, one needs the utility ) Tj /F3 10 Tf 0 0 0 rg (inspect.getfullargspec) Tj /F1 10 Tf 0 0 0 rg (, new) Tj T* 0 Tw (in Python 3 \(and deprecated in favor of ) Tj /F3 10 Tf 0 0 0 rg (inspect.signature ) Tj /F1 10 Tf 0 0 0 rg (in Python 3.5\):) Tj T* ET Q Q q 1 0 0 1 62.69291 94.82362 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 144 re B* Q q .960784 .960784 .862745 rg n 0 120 6 12 re f* .960784 .960784 .862745 rg n 6 120 6 12 re f* .960784 .960784 .862745 rg n 12 120 6 12 re f* .960784 .960784 .862745 rg n 24 120 24 12 re f* .960784 .960784 .862745 rg n 54 120 42 12 re f* .960784 .960784 .862745 rg n 102 120 36 12 re f* .960784 .960784 .862745 rg n 144 120 84 12 re f* .960784 .960784 .862745 rg n 0 108 6 12 re f* .960784 .960784 .862745 rg n 6 108 6 12 re f* .960784 .960784 .862745 rg n 12 108 6 12 re f* .960784 .960784 .862745 rg n 24 108 42 12 re f* .960784 .960784 .862745 rg n 72 108 6 12 re f* .960784 .960784 .862745 rg n 84 108 84 12 re f* .960784 .960784 .862745 rg n 168 108 6 12 re f* .960784 .960784 .862745 rg n 174 108 6 12 re f* .960784 .960784 .862745 rg n 180 108 6 12 re f* .960784 .960784 .862745 rg n 0 96 6 12 re f* .960784 .960784 .862745 rg n 6 96 6 12 re f* .960784 .960784 .862745 rg n 12 96 6 12 re f* .960784 .960784 .862745 rg n 24 96 42 12 re f* .960784 .960784 .862745 rg n 66 96 6 12 re f* .960784 .960784 .862745 rg n 72 96 24 12 re f* .960784 .960784 .862745 rg n 0 84 6 12 re f* .960784 .960784 .862745 rg n 6 84 18 12 re f* .960784 .960784 .862745 rg n 24 84 6 12 re f* .960784 .960784 .862745 rg n 36 84 18 12 re f* .960784 .960784 .862745 rg n 54 84 6 12 re f* .960784 .960784 .862745 rg n 66 84 18 12 re f* .960784 .960784 .862745 rg n 84 84 6 12 re f* .960784 .960784 .862745 rg n 0 72 6 12 re f* .960784 .960784 .862745 rg n 6 72 6 12 re f* .960784 .960784 .862745 rg n 12 72 6 12 re f* .960784 .960784 .862745 rg n 24 72 42 12 re f* .960784 .960784 .862745 rg n 66 72 6 12 re f* .960784 .960784 .862745 rg n 72 72 42 12 re f* .960784 .960784 .862745 rg n 0 60 36 12 re f* .960784 .960784 .862745 rg n 0 48 6 12 re f* .960784 .960784 .862745 rg n 6 48 6 12 re f* .960784 .960784 .862745 rg n 12 48 6 12 re f* .960784 .960784 .862745 rg n 24 48 42 12 re f* .960784 .960784 .862745 rg n 66 48 6 12 re f* .960784 .960784 .862745 rg n 72 48 30 12 re f* .960784 .960784 .862745 rg n 0 36 24 12 re f* .960784 .960784 .862745 rg n 0 24 6 12 re f* .960784 .960784 .862745 rg n 6 24 6 12 re f* .960784 .960784 .862745 rg n 12 24 6 12 re f* .960784 .960784 .862745 rg n 24 24 42 12 re f* .960784 .960784 .862745 rg n 66 24 6 12 re f* .960784 .960784 .862745 rg n 72 24 48 12 re f* .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 6 12 re f* .960784 .960784 .862745 rg n 30 12 6 12 re f* .960784 .960784 .862745 rg n 0 0 6 12 re f* .960784 .960784 .862745 rg n 6 0 6 12 re f* .960784 .960784 .862745 rg n 12 0 6 12 re f* .960784 .960784 .862745 rg n 24 0 42 12 re f* .960784 .960784 .862745 rg n 66 0 6 12 re f* .960784 .960784 .862745 rg n 72 0 60 12 re f* BT 1 0 0 1 0 122 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (from) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 0 1 rg (inspect) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (import) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (getfullargspec) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (argspec) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (getfullargspec) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (argspec) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (args) Tj 0 0 0 rg T* 0 0 0 rg ([) Tj .729412 .129412 .129412 rg ('x') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('y') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('z') Tj 0 0 0 rg (]) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (argspec) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (varargs) Tj 0 0 0 rg T* .729412 .129412 .129412 rg ('args') Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (argspec) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (varkw) Tj 0 0 0 rg T* .729412 .129412 .129412 rg ('kw') Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (argspec) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (defaults) Tj 0 0 0 rg T* 0 0 0 rg (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (argspec) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (kwonlyargs) Tj 0 0 0 rg T* ET Q Q Q Q Q endstream endobj 110 0 obj << /Length 16595 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 727.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 12 12 re f* .960784 .960784 .862745 rg n 0 0 6 12 re f* .960784 .960784 .862745 rg n 6 0 6 12 re f* .960784 .960784 .862745 rg n 12 0 6 12 re f* .960784 .960784 .862745 rg n 24 0 42 12 re f* .960784 .960784 .862745 rg n 66 0 6 12 re f* .960784 .960784 .862745 rg n 72 0 84 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F3 10 Tf 0 0 0 rg ([]) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (argspec) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (kwonlydefaults) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 707.8236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (You can check that the ) Tj /F3 10 Tf 0 0 0 rg (__annotations__ ) Tj /F1 10 Tf 0 0 0 rg (dictionary is preserved:) Tj T* ET Q Q q 1 0 0 1 62.69291 662.6236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 6 12 re f* .960784 .960784 .862745 rg n 30 12 6 12 re f* .960784 .960784 .862745 rg n 36 12 90 12 re f* .960784 .960784 .862745 rg n 132 12 12 12 re f* .960784 .960784 .862745 rg n 150 12 6 12 re f* .960784 .960784 .862745 rg n 156 12 6 12 re f* .960784 .960784 .862745 rg n 162 12 66 12 re f* .960784 .960784 .862745 rg n 228 12 6 12 re f* .960784 .960784 .862745 rg n 234 12 90 12 re f* .960784 .960784 .862745 rg n 0 0 24 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__annotations__) Tj 0 0 0 rg ( ) Tj /F5 10 Tf .666667 .133333 1 rg (is) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__wrapped__) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__annotations__) Tj 0 0 0 rg T* 0 .501961 0 rg (True) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 606.6236 cm q BT 1 0 0 1 0 38 Tm .84284 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here ) Tj /F3 10 Tf 0 0 0 rg (f.__wrapped__ ) Tj /F1 10 Tf 0 0 0 rg (is the original undecorated function. Such an attribute is added to be consistent) Tj T* 0 Tw 1.36998 Tw (with the way ) Tj /F3 10 Tf 0 0 0 rg (functools.update_wrapper ) Tj /F1 10 Tf 0 0 0 rg (work. Another attribute which is copied from the original) Tj T* 0 Tw .588651 Tw (function is ) Tj /F3 10 Tf 0 0 0 rg (__qualname__) Tj /F1 10 Tf 0 0 0 rg (, the qualified name. This is an attribute which is present starting from Python) Tj T* 0 Tw (3.3.) Tj T* ET Q Q q 1 0 0 1 62.69291 573.6236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F3 17.5 Tf 0 0 0 rg (decorator.decorator) Tj T* ET Q Q q 1 0 0 1 62.69291 519.6236 cm q BT 1 0 0 1 0 38 Tm .643876 Tw 12 TL /F1 10 Tf 0 0 0 rg (It may be annoying to write a caller function \(like the ) Tj /F3 10 Tf 0 0 0 rg (_trace ) Tj /F1 10 Tf 0 0 0 rg (function above\) and then a trivial wrapper) Tj T* 0 Tw 2.056342 Tw (\() Tj /F3 10 Tf 0 0 0 rg (def) Tj ( ) Tj (trace\(f\):) Tj ( ) Tj (return) Tj ( ) Tj (decorate\(f,) Tj ( ) Tj (_trace\)) Tj /F1 10 Tf 0 0 0 rg (\) every time. For this reason, the ) Tj /F3 10 Tf 0 0 0 rg (decorator) Tj T* 0 Tw .49284 Tw /F1 10 Tf 0 0 0 rg (module provides an easy shortcut to convert the caller function into a signature-preserving decorator: the) Tj T* 0 Tw /F3 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf 0 0 0 rg (function:) Tj T* ET Q Q q 1 0 0 1 62.69291 462.4236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q .960784 .960784 .862745 rg n 0 24 6 12 re f* .960784 .960784 .862745 rg n 6 24 6 12 re f* .960784 .960784 .862745 rg n 12 24 6 12 re f* .960784 .960784 .862745 rg n 24 24 24 12 re f* .960784 .960784 .862745 rg n 54 24 54 12 re f* .960784 .960784 .862745 rg n 114 24 36 12 re f* .960784 .960784 .862745 rg n 156 24 54 12 re f* .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 30 12 re f* .960784 .960784 .862745 rg n 54 12 6 12 re f* .960784 .960784 .862745 rg n 60 12 54 12 re f* .960784 .960784 .862745 rg n 114 12 6 12 re f* .960784 .960784 .862745 rg n 120 12 42 12 re f* .960784 .960784 .862745 rg n 162 12 6 12 re f* .960784 .960784 .862745 rg n 0 0 54 12 re f* .960784 .960784 .862745 rg n 54 0 6 12 re f* .960784 .960784 .862745 rg n 60 0 36 12 re f* .960784 .960784 .862745 rg n 96 0 6 12 re f* .960784 .960784 .862745 rg n 108 0 48 12 re f* .960784 .960784 .862745 rg n 162 0 6 12 re f* .960784 .960784 .862745 rg n 174 0 36 12 re f* .960784 .960784 .862745 rg n 216 0 48 12 re f* .960784 .960784 .862745 rg n 270 0 24 12 re f* .960784 .960784 .862745 rg n 300 0 6 12 re f* .960784 .960784 .862745 rg n 312 0 54 12 re f* BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (from) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 0 1 rg (decorator) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (import) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (decorator) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (decorator) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__doc__) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* 0 0 0 rg (decorator) Tj 0 0 0 rg (\() Tj 0 0 0 rg (caller) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (converts) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (a) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (caller) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (function) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (into) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (a) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (decorator) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 406.4236 cm q BT 1 0 0 1 0 38 Tm 1.319982 Tw 12 TL /F1 10 Tf 0 0 0 rg (The ) Tj /F3 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf 0 0 0 rg (function can be used as a signature-changing decorator, just as ) Tj /F3 10 Tf 0 0 0 rg (classmethod ) Tj /F1 10 Tf 0 0 0 rg (and) Tj T* 0 Tw 1.945976 Tw /F3 10 Tf 0 0 0 rg (staticmethod) Tj /F1 10 Tf 0 0 0 rg (. However, ) Tj /F3 10 Tf 0 0 0 rg (classmethod ) Tj /F1 10 Tf 0 0 0 rg (and ) Tj /F3 10 Tf 0 0 0 rg (staticmethod ) Tj /F1 10 Tf 0 0 0 rg (return generic objects which are not) Tj T* 0 Tw 1.086342 Tw (callable, while ) Tj /F3 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf 0 0 0 rg (returns signature-preserving decorators, i.e. functions of a single argument.) Tj T* 0 Tw (For instance, you can write directly) Tj T* ET Q Q q 1 0 0 1 62.69291 325.2236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 72 re B* Q q .960784 .960784 .862745 rg n 0 48 6 12 re f* .960784 .960784 .862745 rg n 6 48 6 12 re f* .960784 .960784 .862745 rg n 12 48 6 12 re f* .960784 .960784 .862745 rg n 24 48 60 12 re f* .960784 .960784 .862745 rg n 0 36 18 12 re f* .960784 .960784 .862745 rg n 24 36 18 12 re f* .960784 .960784 .862745 rg n 48 36 30 12 re f* .960784 .960784 .862745 rg n 78 36 6 12 re f* .960784 .960784 .862745 rg n 84 36 6 12 re f* .960784 .960784 .862745 rg n 90 36 6 12 re f* .960784 .960784 .862745 rg n 102 36 6 12 re f* .960784 .960784 .862745 rg n 108 36 24 12 re f* .960784 .960784 .862745 rg n 132 36 6 12 re f* .960784 .960784 .862745 rg n 144 36 12 12 re f* .960784 .960784 .862745 rg n 156 36 12 12 re f* .960784 .960784 .862745 rg n 168 36 12 12 re f* .960784 .960784 .862745 rg n 0 24 18 12 re f* .960784 .960784 .862745 rg n 48 24 30 12 re f* .960784 .960784 .862745 rg n 84 24 6 12 re f* .960784 .960784 .862745 rg n 96 24 24 12 re f* .960784 .960784 .862745 rg n 120 24 6 12 re f* .960784 .960784 .862745 rg n 126 24 24 12 re f* .960784 .960784 .862745 rg n 150 24 6 12 re f* .960784 .960784 .862745 rg n 156 24 6 12 re f* .960784 .960784 .862745 rg n 162 24 12 12 re f* .960784 .960784 .862745 rg n 174 24 6 12 re f* .960784 .960784 .862745 rg n 186 24 12 12 re f* .960784 .960784 .862745 rg n 198 24 6 12 re f* .960784 .960784 .862745 rg n 210 24 6 12 re f* .960784 .960784 .862745 rg n 222 24 6 12 re f* .960784 .960784 .862745 rg n 228 24 6 12 re f* .960784 .960784 .862745 rg n 234 24 6 12 re f* .960784 .960784 .862745 rg n 246 24 12 12 re f* .960784 .960784 .862745 rg n 258 24 6 12 re f* .960784 .960784 .862745 rg n 264 24 6 12 re f* .960784 .960784 .862745 rg n 270 24 12 12 re f* .960784 .960784 .862745 rg n 288 24 18 12 re f* .960784 .960784 .862745 rg n 312 24 6 12 re f* .960784 .960784 .862745 rg n 324 24 12 12 re f* .960784 .960784 .862745 rg n 342 24 36 12 re f* .960784 .960784 .862745 rg n 378 24 6 12 re f* .960784 .960784 .862745 rg n 384 24 12 12 re f* .960784 .960784 .862745 rg n 396 24 12 12 re f* .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 48 12 30 12 re f* .960784 .960784 .862745 rg n 78 12 6 12 re f* .960784 .960784 .862745 rg n 84 12 48 12 re f* .960784 .960784 .862745 rg n 138 12 12 12 re f* .960784 .960784 .862745 rg n 150 12 60 12 re f* .960784 .960784 .862745 rg n 216 12 12 12 re f* .960784 .960784 .862745 rg n 228 12 18 12 re f* .960784 .960784 .862745 rg n 246 12 12 12 re f* .960784 .960784 .862745 rg n 258 12 12 12 re f* .960784 .960784 .862745 rg n 276 12 6 12 re f* .960784 .960784 .862745 rg n 288 12 6 12 re f* .960784 .960784 .862745 rg n 294 12 6 12 re f* .960784 .960784 .862745 rg n 300 12 6 12 re f* .960784 .960784 .862745 rg n 306 12 48 12 re f* .960784 .960784 .862745 rg n 354 12 6 12 re f* .960784 .960784 .862745 rg n 366 12 24 12 re f* .960784 .960784 .862745 rg n 390 12 6 12 re f* .960784 .960784 .862745 rg n 402 12 30 12 re f* .960784 .960784 .862745 rg n 432 12 12 12 re f* .960784 .960784 .862745 rg n 0 0 18 12 re f* .960784 .960784 .862745 rg n 48 0 36 12 re f* .960784 .960784 .862745 rg n 90 0 6 12 re f* .960784 .960784 .862745 rg n 96 0 6 12 re f* .960784 .960784 .862745 rg n 102 0 6 12 re f* .960784 .960784 .862745 rg n 108 0 24 12 re f* .960784 .960784 .862745 rg n 132 0 6 12 re f* .960784 .960784 .862745 rg n 144 0 12 12 re f* .960784 .960784 .862745 rg n 156 0 12 12 re f* .960784 .960784 .862745 rg n 168 0 6 12 re f* BT 1 0 0 1 0 50 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj .666667 .133333 1 rg (@decorator) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (trace) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (kwstr) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg (', ') Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (join) Tj 0 0 0 rg (\() Tj .729412 .129412 .129412 rg (') Tj /F5 10 Tf .733333 .4 .533333 rg (%r) Tj /F3 10 Tf .729412 .129412 .129412 rg (: ) Tj /F5 10 Tf .733333 .4 .533333 rg (%r) Tj /F3 10 Tf .729412 .129412 .129412 rg (') Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (%) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (\() Tj 0 0 0 rg (k) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (kw) Tj 0 0 0 rg ([) Tj 0 0 0 rg (k) Tj 0 0 0 rg (]\)) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (for) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (k) Tj 0 0 0 rg ( ) Tj /F5 10 Tf .666667 .133333 1 rg (in) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (sorted) Tj 0 0 0 rg (\() Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\)\)) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ("calling ) Tj /F5 10 Tf .733333 .4 .533333 rg (%s) Tj /F3 10 Tf .729412 .129412 .129412 rg ( with args ) Tj /F5 10 Tf .733333 .4 .533333 rg (%s) Tj /F3 10 Tf .729412 .129412 .129412 rg (, {) Tj /F5 10 Tf .733333 .4 .533333 rg (%s) Tj /F3 10 Tf .729412 .129412 .129412 rg (}") Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (%) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__name__) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (kwstr) Tj 0 0 0 rg (\)\)) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (f) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 305.2236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (and now ) Tj /F3 10 Tf 0 0 0 rg (trace ) Tj /F1 10 Tf 0 0 0 rg (will be a decorator.) Tj T* ET Q Q q 1 0 0 1 62.69291 260.0236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 30 12 re f* .960784 .960784 .862745 rg n 0 0 6 12 re f* .960784 .960784 .862745 rg n 6 0 48 12 re f* .960784 .960784 .862745 rg n 60 0 30 12 re f* .960784 .960784 .862745 rg n 96 0 12 12 re f* .960784 .960784 .862745 rg n 114 0 6 12 re f* .960784 .960784 .862745 rg n 120 0 6 12 re f* .960784 .960784 .862745 rg n 126 0 18 12 re f* .960784 .960784 .862745 rg n 144 0 6 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (trace) Tj 0 0 0 rg T* .4 .4 .4 rg (<) Tj 0 0 0 rg (function) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (trace) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (at) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (0) Tj 0 0 0 rg (x) Tj .4 .4 .4 rg (...) Tj (>) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 240.0236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Here is an example of usage:) Tj T* ET Q Q q 1 0 0 1 62.69291 158.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 72 re B* Q q .960784 .960784 .862745 rg n 0 48 6 12 re f* .960784 .960784 .862745 rg n 6 48 6 12 re f* .960784 .960784 .862745 rg n 12 48 6 12 re f* .960784 .960784 .862745 rg n 24 48 36 12 re f* .960784 .960784 .862745 rg n 0 36 18 12 re f* .960784 .960784 .862745 rg n 24 36 18 12 re f* .960784 .960784 .862745 rg n 48 36 24 12 re f* .960784 .960784 .862745 rg n 72 36 18 12 re f* .960784 .960784 .862745 rg n 96 36 24 12 re f* .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 24 12 re f* .960784 .960784 .862745 rg n 48 12 12 12 re f* .960784 .960784 .862745 rg n 0 0 42 12 re f* .960784 .960784 .862745 rg n 48 0 24 12 re f* .960784 .960784 .862745 rg n 78 0 24 12 re f* .960784 .960784 .862745 rg n 108 0 24 12 re f* .960784 .960784 .862745 rg n 138 0 18 12 re f* .960784 .960784 .862745 rg n 162 0 12 12 re f* BT 1 0 0 1 0 50 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj .666667 .133333 1 rg (@trace) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (func) Tj 0 0 0 rg (\(\):) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (pass) Tj /F3 10 Tf 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg T* 0 0 0 rg (calling) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (with) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (args) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (\(\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg ({}) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 125.8236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F3 17.5 Tf 0 0 0 rg (blocking) Tj T* ET Q Q q 1 0 0 1 62.69291 83.82362 cm q BT 1 0 0 1 0 26 Tm 1.224692 Tw 12 TL /F1 10 Tf 0 0 0 rg (Sometimes one has to deal with blocking resources, such as ) Tj /F3 10 Tf 0 0 0 rg (stdin) Tj /F1 10 Tf 0 0 0 rg (, and sometimes it is best to have) Tj T* 0 Tw .266235 Tw (back a "busy" message than to block everything. This behavior can be implemented with a suitable family) Tj T* 0 Tw (of decorators, where the parameter is the busy message:) Tj T* ET Q Q endstream endobj 111 0 obj << /Length 18621 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 583.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 180 re B* Q q .960784 .960784 .862745 rg n 0 156 18 12 re f* .960784 .960784 .862745 rg n 24 156 48 12 re f* .960784 .960784 .862745 rg n 72 156 6 12 re f* .960784 .960784 .862745 rg n 78 156 54 12 re f* .960784 .960784 .862745 rg n 132 156 12 12 re f* .960784 .960784 .862745 rg n 24 144 18 12 re f* .960784 .960784 .862745 rg n 48 144 54 12 re f* .960784 .960784 .862745 rg n 102 144 6 12 re f* .960784 .960784 .862745 rg n 108 144 6 12 re f* .960784 .960784 .862745 rg n 114 144 6 12 re f* .960784 .960784 .862745 rg n 126 144 6 12 re f* .960784 .960784 .862745 rg n 132 144 24 12 re f* .960784 .960784 .862745 rg n 156 144 6 12 re f* .960784 .960784 .862745 rg n 168 144 12 12 re f* .960784 .960784 .862745 rg n 180 144 12 12 re f* .960784 .960784 .862745 rg n 192 144 12 12 re f* .960784 .960784 .862745 rg n 48 132 12 12 re f* .960784 .960784 .862745 rg n 66 132 18 12 re f* .960784 .960784 .862745 rg n 90 132 42 12 re f* .960784 .960784 .862745 rg n 132 132 6 12 re f* .960784 .960784 .862745 rg n 138 132 6 12 re f* .960784 .960784 .862745 rg n 144 132 6 12 re f* .960784 .960784 .862745 rg n 156 132 48 12 re f* .960784 .960784 .862745 rg n 204 132 12 12 re f* .960784 .960784 .862745 rg n 228 132 114 12 re f* .960784 .960784 .862745 rg n 72 120 18 12 re f* .960784 .960784 .862745 rg n 96 120 60 12 re f* .960784 .960784 .862745 rg n 156 120 18 12 re f* .960784 .960784 .862745 rg n 96 108 6 12 re f* .960784 .960784 .862745 rg n 102 108 6 12 re f* .960784 .960784 .862745 rg n 108 108 36 12 re f* .960784 .960784 .862745 rg n 150 108 6 12 re f* .960784 .960784 .862745 rg n 162 108 6 12 re f* .960784 .960784 .862745 rg n 168 108 6 12 re f* .960784 .960784 .862745 rg n 174 108 6 12 re f* .960784 .960784 .862745 rg n 180 108 24 12 re f* .960784 .960784 .862745 rg n 204 108 6 12 re f* .960784 .960784 .862745 rg n 216 108 12 12 re f* .960784 .960784 .862745 rg n 228 108 12 12 re f* .960784 .960784 .862745 rg n 240 108 6 12 re f* .960784 .960784 .862745 rg n 72 96 6 12 re f* .960784 .960784 .862745 rg n 78 96 6 12 re f* .960784 .960784 .862745 rg n 84 96 36 12 re f* .960784 .960784 .862745 rg n 126 96 6 12 re f* .960784 .960784 .862745 rg n 138 96 54 12 re f* .960784 .960784 .862745 rg n 192 96 6 12 re f* .960784 .960784 .862745 rg n 198 96 36 12 re f* .960784 .960784 .862745 rg n 234 96 6 12 re f* .960784 .960784 .862745 rg n 240 96 24 12 re f* .960784 .960784 .862745 rg n 264 96 6 12 re f* .960784 .960784 .862745 rg n 276 96 60 12 re f* .960784 .960784 .862745 rg n 336 96 6 12 re f* .960784 .960784 .862745 rg n 72 84 6 12 re f* .960784 .960784 .862745 rg n 78 84 6 12 re f* .960784 .960784 .862745 rg n 84 84 36 12 re f* .960784 .960784 .862745 rg n 120 84 6 12 re f* .960784 .960784 .862745 rg n 126 84 30 12 re f* .960784 .960784 .862745 rg n 156 84 12 12 re f* .960784 .960784 .862745 rg n 72 72 36 12 re f* .960784 .960784 .862745 rg n 114 72 54 12 re f* .960784 .960784 .862745 rg n 48 60 24 12 re f* .960784 .960784 .862745 rg n 78 60 6 12 re f* .960784 .960784 .862745 rg n 84 60 6 12 re f* .960784 .960784 .862745 rg n 90 60 36 12 re f* .960784 .960784 .862745 rg n 126 60 6 12 re f* .960784 .960784 .862745 rg n 132 60 42 12 re f* .960784 .960784 .862745 rg n 174 60 18 12 re f* .960784 .960784 .862745 rg n 72 48 36 12 re f* .960784 .960784 .862745 rg n 114 48 54 12 re f* .960784 .960784 .862745 rg n 48 36 24 12 re f* .960784 .960784 .862745 rg n 72 36 6 12 re f* .960784 .960784 .862745 rg n 90 36 282 12 re f* .960784 .960784 .862745 rg n 72 24 18 12 re f* .960784 .960784 .862745 rg n 96 24 6 12 re f* .960784 .960784 .862745 rg n 102 24 6 12 re f* .960784 .960784 .862745 rg n 108 24 36 12 re f* .960784 .960784 .862745 rg n 72 12 36 12 re f* .960784 .960784 .862745 rg n 114 12 6 12 re f* .960784 .960784 .862745 rg n 120 12 6 12 re f* .960784 .960784 .862745 rg n 126 12 36 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 54 12 re f* .960784 .960784 .862745 rg n 120 0 6 12 re f* .960784 .960784 .862745 rg n 126 0 54 12 re f* .960784 .960784 .862745 rg n 180 0 6 12 re f* BT 1 0 0 1 0 158 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (blocking) Tj 0 0 0 rg (\() Tj 0 0 0 rg (not_avail) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (_blocking) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (if) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf .666667 .133333 1 rg (not) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (hasattr) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("thread") Tj 0 0 0 rg (\):) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# no thread running) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (set_result) Tj 0 0 0 rg (\(\):) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (result) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (thread) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (threading) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Thread) Tj 0 0 0 rg (\() Tj 0 .501961 0 rg (None) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (set_result) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (thread) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (start) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (not_avail) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (elif) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (thread) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (isAlive) Tj 0 0 0 rg (\(\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (not_avail) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (else) Tj /F3 10 Tf 0 0 0 rg (:) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# the thread is ended, return the stored result) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (del) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (thread) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (result) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (decorator) Tj 0 0 0 rg (\() Tj 0 0 0 rg (_blocking) Tj 0 0 0 rg (\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 551.8236 cm q BT 1 0 0 1 0 14 Tm 1.010651 Tw 12 TL /F1 10 Tf 0 0 0 rg (Functions decorated with ) Tj /F3 10 Tf 0 0 0 rg (blocking ) Tj /F1 10 Tf 0 0 0 rg (will return a busy message if the resource is unavailable, and the) Tj T* 0 Tw (intended result if the resource is available. For instance:) Tj T* ET Q Q q 1 0 0 1 62.69291 302.6236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 240 re B* Q q .960784 .960784 .862745 rg n 0 216 6 12 re f* .960784 .960784 .862745 rg n 6 216 6 12 re f* .960784 .960784 .862745 rg n 12 216 6 12 re f* .960784 .960784 .862745 rg n 24 216 54 12 re f* .960784 .960784 .862745 rg n 78 216 6 12 re f* .960784 .960784 .862745 rg n 84 216 102 12 re f* .960784 .960784 .862745 rg n 186 216 6 12 re f* .960784 .960784 .862745 rg n 0 204 18 12 re f* .960784 .960784 .862745 rg n 24 204 18 12 re f* .960784 .960784 .862745 rg n 48 204 54 12 re f* .960784 .960784 .862745 rg n 102 204 18 12 re f* .960784 .960784 .862745 rg n 0 192 18 12 re f* .960784 .960784 .862745 rg n 48 192 24 12 re f* .960784 .960784 .862745 rg n 72 192 6 12 re f* .960784 .960784 .862745 rg n 78 192 30 12 re f* .960784 .960784 .862745 rg n 108 192 6 12 re f* .960784 .960784 .862745 rg n 114 192 6 12 re f* .960784 .960784 .862745 rg n 120 192 6 12 re f* .960784 .960784 .862745 rg n 132 192 180 12 re f* .960784 .960784 .862745 rg n 0 180 18 12 re f* .960784 .960784 .862745 rg n 48 180 36 12 re f* .960784 .960784 .862745 rg n 90 180 66 12 re f* .960784 .960784 .862745 rg n 0 156 6 12 re f* .960784 .960784 .862745 rg n 6 156 6 12 re f* .960784 .960784 .862745 rg n 12 156 6 12 re f* .960784 .960784 .862745 rg n 24 156 30 12 re f* .960784 .960784 .862745 rg n 54 156 6 12 re f* .960784 .960784 .862745 rg n 60 156 54 12 re f* .960784 .960784 .862745 rg n 114 156 18 12 re f* .960784 .960784 .862745 rg n 144 156 162 12 re f* .960784 .960784 .862745 rg n 0 144 36 12 re f* .960784 .960784 .862745 rg n 42 144 24 12 re f* .960784 .960784 .862745 rg n 72 144 18 12 re f* .960784 .960784 .862745 rg n 0 120 6 12 re f* .960784 .960784 .862745 rg n 6 120 6 12 re f* .960784 .960784 .862745 rg n 12 120 6 12 re f* .960784 .960784 .862745 rg n 24 120 24 12 re f* .960784 .960784 .862745 rg n 48 120 6 12 re f* .960784 .960784 .862745 rg n 54 120 30 12 re f* .960784 .960784 .862745 rg n 84 120 6 12 re f* .960784 .960784 .862745 rg n 90 120 6 12 re f* .960784 .960784 .862745 rg n 96 120 6 12 re f* .960784 .960784 .862745 rg n 0 108 6 12 re f* .960784 .960784 .862745 rg n 6 108 6 12 re f* .960784 .960784 .862745 rg n 12 108 6 12 re f* .960784 .960784 .862745 rg n 24 108 30 12 re f* .960784 .960784 .862745 rg n 54 108 6 12 re f* .960784 .960784 .862745 rg n 60 108 54 12 re f* .960784 .960784 .862745 rg n 114 108 18 12 re f* .960784 .960784 .862745 rg n 144 108 162 12 re f* .960784 .960784 .862745 rg n 0 96 36 12 re f* .960784 .960784 .862745 rg n 42 96 24 12 re f* .960784 .960784 .862745 rg n 72 96 18 12 re f* .960784 .960784 .862745 rg n 0 72 6 12 re f* .960784 .960784 .862745 rg n 6 72 6 12 re f* .960784 .960784 .862745 rg n 12 72 6 12 re f* .960784 .960784 .862745 rg n 24 72 24 12 re f* .960784 .960784 .862745 rg n 48 72 6 12 re f* .960784 .960784 .862745 rg n 54 72 30 12 re f* .960784 .960784 .862745 rg n 84 72 6 12 re f* .960784 .960784 .862745 rg n 90 72 6 12 re f* .960784 .960784 .862745 rg n 96 72 6 12 re f* .960784 .960784 .862745 rg n 0 60 6 12 re f* .960784 .960784 .862745 rg n 6 60 6 12 re f* .960784 .960784 .862745 rg n 12 60 6 12 re f* .960784 .960784 .862745 rg n 24 60 30 12 re f* .960784 .960784 .862745 rg n 54 60 6 12 re f* .960784 .960784 .862745 rg n 60 60 54 12 re f* .960784 .960784 .862745 rg n 114 60 18 12 re f* .960784 .960784 .862745 rg n 144 60 162 12 re f* .960784 .960784 .862745 rg n 0 48 36 12 re f* .960784 .960784 .862745 rg n 42 48 24 12 re f* .960784 .960784 .862745 rg n 72 48 18 12 re f* .960784 .960784 .862745 rg n 0 24 6 12 re f* .960784 .960784 .862745 rg n 6 24 6 12 re f* .960784 .960784 .862745 rg n 12 24 6 12 re f* .960784 .960784 .862745 rg n 24 24 24 12 re f* .960784 .960784 .862745 rg n 48 24 6 12 re f* .960784 .960784 .862745 rg n 54 24 30 12 re f* .960784 .960784 .862745 rg n 84 24 6 12 re f* .960784 .960784 .862745 rg n 90 24 18 12 re f* .960784 .960784 .862745 rg n 108 24 6 12 re f* .960784 .960784 .862745 rg n 126 24 228 12 re f* .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 30 12 re f* .960784 .960784 .862745 rg n 54 12 6 12 re f* .960784 .960784 .862745 rg n 60 12 54 12 re f* .960784 .960784 .862745 rg n 114 12 18 12 re f* .960784 .960784 .862745 rg n 0 0 24 12 re f* .960784 .960784 .862745 rg n 30 0 24 12 re f* BT 1 0 0 1 0 218 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj .666667 .133333 1 rg (@blocking) Tj 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ("Please wait ...") Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (read_data) Tj 0 0 0 rg (\(\):) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (time) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (sleep) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (3) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# simulate a blocking resource) Tj /F3 10 Tf 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("some data") Tj 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (read_data) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# data is not available yet) Tj /F3 10 Tf 0 0 0 rg T* 0 0 0 rg (Please) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (wait) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (...) Tj 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (time) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (sleep) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (read_data) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# data is not available yet) Tj /F3 10 Tf 0 0 0 rg T* 0 0 0 rg (Please) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (wait) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (...) Tj 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (time) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (sleep) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (read_data) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# data is not available yet) Tj /F3 10 Tf 0 0 0 rg T* 0 0 0 rg (Please) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (wait) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (...) Tj 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (time) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (sleep) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (1.1) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# after 3.1 seconds, data is available) Tj /F3 10 Tf 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (read_data) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg T* 0 0 0 rg (some) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (data) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 269.6236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F3 17.5 Tf 0 0 0 rg (decorator\(cls\)) Tj T* ET Q Q q 1 0 0 1 62.69291 239.6236 cm q BT 1 0 0 1 0 14 Tm .441163 Tw 12 TL /F1 10 Tf 0 0 0 rg (The ) Tj /F3 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf 0 0 0 rg (facility can also produce a decorator starting from a class with the signature of a caller.) Tj T* 0 Tw (In such a case the produced generator is able to convert functions into factories of instances of that class.) Tj T* ET Q Q q 1 0 0 1 62.69291 185.6236 cm q BT 1 0 0 1 0 38 Tm 2.853876 Tw 12 TL /F1 10 Tf 0 0 0 rg (As an example, here will I show a decorator which is able to convert a blocking function into an) Tj T* 0 Tw .25811 Tw (asynchronous function. The function, when called, is executed in a separate thread. This is very similar to) Tj T* 0 Tw .453984 Tw (the approach used in the ) Tj /F3 10 Tf 0 0 0 rg (concurrent.futures ) Tj /F1 10 Tf 0 0 0 rg (package. Of course the code here is just an example,) Tj T* 0 Tw (it is not a recommended way of implementing futures. The implementation is the following:) Tj T* ET Q Q q 1 0 0 1 62.69291 80.42362 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 96 re B* Q q .960784 .960784 .862745 rg n 0 72 30 12 re f* .960784 .960784 .862745 rg n 36 72 36 12 re f* .960784 .960784 .862745 rg n 72 72 6 12 re f* .960784 .960784 .862745 rg n 78 72 54 12 re f* .960784 .960784 .862745 rg n 132 72 6 12 re f* .960784 .960784 .862745 rg n 138 72 36 12 re f* .960784 .960784 .862745 rg n 174 72 12 12 re f* .960784 .960784 .862745 rg n 24 60 18 12 re f* .960784 .960784 .862745 rg n 0 48 354 12 re f* .960784 .960784 .862745 rg n 0 36 186 12 re f* .960784 .960784 .862745 rg n 0 24 42 12 re f* .960784 .960784 .862745 rg n 24 12 18 12 re f* .960784 .960784 .862745 rg n 48 12 48 12 re f* .960784 .960784 .862745 rg n 96 12 6 12 re f* .960784 .960784 .862745 rg n 102 12 24 12 re f* .960784 .960784 .862745 rg n 126 12 6 12 re f* .960784 .960784 .862745 rg n 138 12 24 12 re f* .960784 .960784 .862745 rg n 162 12 6 12 re f* .960784 .960784 .862745 rg n 174 12 6 12 re f* .960784 .960784 .862745 rg n 180 12 24 12 re f* .960784 .960784 .862745 rg n 204 12 6 12 re f* .960784 .960784 .862745 rg n 216 12 12 12 re f* .960784 .960784 .862745 rg n 228 12 12 12 re f* .960784 .960784 .862745 rg n 240 12 12 12 re f* .960784 .960784 .862745 rg n 48 0 18 12 re f* .960784 .960784 .862745 rg n 66 0 6 12 re f* BT 1 0 0 1 0 74 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (class) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 0 1 rg (Future) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (threading) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Thread) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf .729412 .129412 .129412 rg (""") Tj T* ( A class converting blocking functions into asynchronous) Tj T* ( functions by using threads.) Tj T* ( """) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (__init__) Tj 0 0 0 rg (\() Tj 0 .501961 0 rg (self) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (try) Tj /F3 10 Tf 0 0 0 rg (:) Tj 0 0 0 rg T* ET Q Q Q Q Q endstream endobj 112 0 obj << /Length 18427 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 595.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 168 re B* Q q .960784 .960784 .862745 rg n 72 144 42 12 re f* .960784 .960784 .862745 rg n 120 144 6 12 re f* .960784 .960784 .862745 rg n 132 144 24 12 re f* .960784 .960784 .862745 rg n 156 144 6 12 re f* .960784 .960784 .862745 rg n 162 144 42 12 re f* .960784 .960784 .862745 rg n 48 132 36 12 re f* .960784 .960784 .862745 rg n 90 132 84 12 re f* .960784 .960784 .862745 rg n 174 132 6 12 re f* .960784 .960784 .862745 rg n 192 132 258 12 re f* .960784 .960784 .862745 rg n 72 120 42 12 re f* .960784 .960784 .862745 rg n 120 120 6 12 re f* .960784 .960784 .862745 rg n 132 120 24 12 re f* .960784 .960784 .862745 rg n 156 120 6 12 re f* .960784 .960784 .862745 rg n 162 120 42 12 re f* .960784 .960784 .862745 rg n 210 120 6 12 re f* .960784 .960784 .862745 rg n 222 120 54 12 re f* .960784 .960784 .862745 rg n 276 120 6 12 re f* .960784 .960784 .862745 rg n 282 120 30 12 re f* .960784 .960784 .862745 rg n 312 120 6 12 re f* .960784 .960784 .862745 rg n 318 120 6 12 re f* .960784 .960784 .862745 rg n 324 120 6 12 re f* .960784 .960784 .862745 rg n 48 108 24 12 re f* .960784 .960784 .862745 rg n 78 108 6 12 re f* .960784 .960784 .862745 rg n 90 108 6 12 re f* .960784 .960784 .862745 rg n 96 108 12 12 re f* .960784 .960784 .862745 rg n 108 108 6 12 re f* .960784 .960784 .862745 rg n 114 108 12 12 re f* .960784 .960784 .862745 rg n 126 108 6 12 re f* .960784 .960784 .862745 rg n 138 108 6 12 re f* .960784 .960784 .862745 rg n 150 108 6 12 re f* .960784 .960784 .862745 rg n 156 108 24 12 re f* .960784 .960784 .862745 rg n 180 108 6 12 re f* .960784 .960784 .862745 rg n 186 108 48 12 re f* .960784 .960784 .862745 rg n 234 108 6 12 re f* .960784 .960784 .862745 rg n 246 108 24 12 re f* .960784 .960784 .862745 rg n 270 108 6 12 re f* .960784 .960784 .862745 rg n 276 108 42 12 re f* .960784 .960784 .862745 rg n 318 108 12 12 re f* .960784 .960784 .862745 rg n 48 84 18 12 re f* .960784 .960784 .862745 rg n 72 84 72 12 re f* .960784 .960784 .862745 rg n 144 84 18 12 re f* .960784 .960784 .862745 rg n 72 72 24 12 re f* .960784 .960784 .862745 rg n 96 72 6 12 re f* .960784 .960784 .862745 rg n 102 72 42 12 re f* .960784 .960784 .862745 rg n 150 72 6 12 re f* .960784 .960784 .862745 rg n 162 72 24 12 re f* .960784 .960784 .862745 rg n 186 72 6 12 re f* .960784 .960784 .862745 rg n 192 72 6 12 re f* .960784 .960784 .862745 rg n 198 72 24 12 re f* .960784 .960784 .862745 rg n 222 72 6 12 re f* .960784 .960784 .862745 rg n 234 72 12 12 re f* .960784 .960784 .862745 rg n 246 72 12 12 re f* .960784 .960784 .862745 rg n 258 72 6 12 re f* .960784 .960784 .862745 rg n 48 60 30 12 re f* .960784 .960784 .862745 rg n 78 60 6 12 re f* .960784 .960784 .862745 rg n 84 60 36 12 re f* .960784 .960784 .862745 rg n 120 60 6 12 re f* .960784 .960784 .862745 rg n 132 60 24 12 re f* .960784 .960784 .862745 rg n 156 60 6 12 re f* .960784 .960784 .862745 rg n 162 60 6 12 re f* .960784 .960784 .862745 rg n 168 60 48 12 re f* .960784 .960784 .862745 rg n 216 60 6 12 re f* .960784 .960784 .862745 rg n 222 60 36 12 re f* .960784 .960784 .862745 rg n 258 60 6 12 re f* .960784 .960784 .862745 rg n 264 60 72 12 re f* .960784 .960784 .862745 rg n 336 60 6 12 re f* .960784 .960784 .862745 rg n 348 60 24 12 re f* .960784 .960784 .862745 rg n 372 60 6 12 re f* .960784 .960784 .862745 rg n 378 60 24 12 re f* .960784 .960784 .862745 rg n 402 60 6 12 re f* .960784 .960784 .862745 rg n 48 48 24 12 re f* .960784 .960784 .862745 rg n 72 48 6 12 re f* .960784 .960784 .862745 rg n 78 48 30 12 re f* .960784 .960784 .862745 rg n 108 48 12 12 re f* .960784 .960784 .862745 rg n 24 24 18 12 re f* .960784 .960784 .862745 rg n 48 24 36 12 re f* .960784 .960784 .862745 rg n 84 24 6 12 re f* .960784 .960784 .862745 rg n 90 24 24 12 re f* .960784 .960784 .862745 rg n 114 24 12 12 re f* .960784 .960784 .862745 rg n 48 12 24 12 re f* .960784 .960784 .862745 rg n 72 12 6 12 re f* .960784 .960784 .862745 rg n 78 12 24 12 re f* .960784 .960784 .862745 rg n 102 12 12 12 re f* .960784 .960784 .862745 rg n 48 0 36 12 re f* .960784 .960784 .862745 rg n 90 0 24 12 re f* .960784 .960784 .862745 rg n 114 0 6 12 re f* .960784 .960784 .862745 rg n 120 0 42 12 re f* BT 1 0 0 1 0 146 Tm 12 TL /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (counter) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (counter) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (except) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf .823529 .254902 .227451 rg (AttributeError) Tj /F3 10 Tf 0 0 0 rg (:) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# instantiate the counter at the first call) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj 0 0 0 rg (counter) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (counter) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (itertools) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (count) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (name) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg (') Tj /F5 10 Tf .733333 .4 .533333 rg (%s) Tj /F3 10 Tf .729412 .129412 .129412 rg (-) Tj /F5 10 Tf .733333 .4 .533333 rg (%s) Tj /F3 10 Tf .729412 .129412 .129412 rg (') Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (%) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (\() Tj 0 0 0 rg (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__name__) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (next) Tj 0 0 0 rg (\() Tj 0 0 0 rg (counter) Tj 0 0 0 rg (\)\)) Tj 0 0 0 rg T* T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (func_wrapper) Tj 0 0 0 rg (\(\):) Tj 0 0 0 rg T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (_result) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj 0 .501961 0 rg (super) Tj 0 0 0 rg (\() Tj 0 0 0 rg (Future) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (self) Tj 0 0 0 rg (\)) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__init__) Tj 0 0 0 rg (\() Tj 0 0 0 rg (target) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (func_wrapper) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (name) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (name) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (start) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg T* T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (result) Tj 0 0 0 rg (\() Tj 0 .501961 0 rg (self) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (join) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (_result) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 563.8236 cm q BT 1 0 0 1 0 14 Tm .143984 Tw 12 TL /F1 10 Tf 0 0 0 rg (The decorated function returns a ) Tj /F3 10 Tf 0 0 0 rg (Future ) Tj /F1 10 Tf 0 0 0 rg (object, which has a ) Tj /F3 10 Tf 0 0 0 rg (.result\(\) ) Tj /F1 10 Tf 0 0 0 rg (method which blocks until the) Tj T* 0 Tw (underlying thread finishes and returns the final result. Here is a minimalistic example of usage:) Tj T* ET Q Q q 1 0 0 1 62.69291 422.6236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 132 re B* Q q .960784 .960784 .862745 rg n 0 108 6 12 re f* .960784 .960784 .862745 rg n 6 108 6 12 re f* .960784 .960784 .862745 rg n 12 108 6 12 re f* .960784 .960784 .862745 rg n 24 108 78 12 re f* .960784 .960784 .862745 rg n 108 108 6 12 re f* .960784 .960784 .862745 rg n 120 108 54 12 re f* .960784 .960784 .862745 rg n 174 108 6 12 re f* .960784 .960784 .862745 rg n 180 108 36 12 re f* .960784 .960784 .862745 rg n 216 108 6 12 re f* .960784 .960784 .862745 rg n 0 96 6 12 re f* .960784 .960784 .862745 rg n 6 96 6 12 re f* .960784 .960784 .862745 rg n 12 96 6 12 re f* .960784 .960784 .862745 rg n 24 96 84 12 re f* .960784 .960784 .862745 rg n 0 84 18 12 re f* .960784 .960784 .862745 rg n 24 84 18 12 re f* .960784 .960784 .862745 rg n 48 84 72 12 re f* .960784 .960784 .862745 rg n 120 84 6 12 re f* .960784 .960784 .862745 rg n 126 84 6 12 re f* .960784 .960784 .862745 rg n 132 84 12 12 re f* .960784 .960784 .862745 rg n 0 72 18 12 re f* .960784 .960784 .862745 rg n 48 72 24 12 re f* .960784 .960784 .862745 rg n 72 72 6 12 re f* .960784 .960784 .862745 rg n 78 72 30 12 re f* .960784 .960784 .862745 rg n 108 72 6 12 re f* .960784 .960784 .862745 rg n 114 72 6 12 re f* .960784 .960784 .862745 rg n 120 72 6 12 re f* .960784 .960784 .862745 rg n 126 72 6 12 re f* .960784 .960784 .862745 rg n 0 60 18 12 re f* .960784 .960784 .862745 rg n 48 60 36 12 re f* .960784 .960784 .862745 rg n 90 60 6 12 re f* .960784 .960784 .862745 rg n 0 36 6 12 re f* .960784 .960784 .862745 rg n 6 36 6 12 re f* .960784 .960784 .862745 rg n 12 36 6 12 re f* .960784 .960784 .862745 rg n 24 36 24 12 re f* .960784 .960784 .862745 rg n 54 36 6 12 re f* .960784 .960784 .862745 rg n 66 36 72 12 re f* .960784 .960784 .862745 rg n 138 36 6 12 re f* .960784 .960784 .862745 rg n 144 36 6 12 re f* .960784 .960784 .862745 rg n 150 36 6 12 re f* .960784 .960784 .862745 rg n 0 24 6 12 re f* .960784 .960784 .862745 rg n 6 24 6 12 re f* .960784 .960784 .862745 rg n 12 24 6 12 re f* .960784 .960784 .862745 rg n 24 24 24 12 re f* .960784 .960784 .862745 rg n 54 24 6 12 re f* .960784 .960784 .862745 rg n 66 24 72 12 re f* .960784 .960784 .862745 rg n 138 24 6 12 re f* .960784 .960784 .862745 rg n 144 24 6 12 re f* .960784 .960784 .862745 rg n 150 24 6 12 re f* .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 24 12 re f* .960784 .960784 .862745 rg n 48 12 6 12 re f* .960784 .960784 .862745 rg n 54 12 36 12 re f* .960784 .960784 .862745 rg n 90 12 12 12 re f* .960784 .960784 .862745 rg n 108 12 6 12 re f* .960784 .960784 .862745 rg n 120 12 24 12 re f* .960784 .960784 .862745 rg n 144 12 6 12 re f* .960784 .960784 .862745 rg n 150 12 36 12 re f* .960784 .960784 .862745 rg n 186 12 12 12 re f* .960784 .960784 .862745 rg n 0 0 6 12 re f* BT 1 0 0 1 0 110 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (futurefactory) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (decorator) Tj 0 0 0 rg (\() Tj 0 0 0 rg (Future) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj .666667 .133333 1 rg (@futurefactory) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (long_running) Tj 0 0 0 rg (\() Tj 0 0 0 rg (x) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (time) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (sleep) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (.) Tj .4 .4 .4 rg (5) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (x) Tj 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (fut1) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (long_running) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (fut2) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (long_running) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (fut1) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (result) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (+) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (fut2) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (result) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg T* .4 .4 .4 rg (3) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 389.6236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (contextmanager) Tj T* ET Q Q q 1 0 0 1 62.69291 359.6236 cm q BT 1 0 0 1 0 14 Tm 2.685984 Tw 12 TL /F1 10 Tf 0 0 0 rg (For a long time Python had in its standard library a ) Tj /F3 10 Tf 0 0 0 rg (contextmanager ) Tj /F1 10 Tf 0 0 0 rg (decorator, able to convert) Tj T* 0 Tw (generator functions into ) Tj /F3 10 Tf 0 0 0 rg (GeneratorContextManager ) Tj /F1 10 Tf 0 0 0 rg (factories. For instance if you write) Tj T* ET Q Q q 1 0 0 1 62.69291 266.4236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 84 re B* Q q .960784 .960784 .862745 rg n 0 60 6 12 re f* .960784 .960784 .862745 rg n 6 60 6 12 re f* .960784 .960784 .862745 rg n 12 60 6 12 re f* .960784 .960784 .862745 rg n 24 60 24 12 re f* .960784 .960784 .862745 rg n 54 60 60 12 re f* .960784 .960784 .862745 rg n 120 60 36 12 re f* .960784 .960784 .862745 rg n 162 60 84 12 re f* .960784 .960784 .862745 rg n 0 48 6 12 re f* .960784 .960784 .862745 rg n 6 48 6 12 re f* .960784 .960784 .862745 rg n 12 48 6 12 re f* .960784 .960784 .862745 rg n 24 48 90 12 re f* .960784 .960784 .862745 rg n 0 36 18 12 re f* .960784 .960784 .862745 rg n 24 36 18 12 re f* .960784 .960784 .862745 rg n 48 36 72 12 re f* .960784 .960784 .862745 rg n 120 36 6 12 re f* .960784 .960784 .862745 rg n 126 36 36 12 re f* .960784 .960784 .862745 rg n 162 36 6 12 re f* .960784 .960784 .862745 rg n 174 36 30 12 re f* .960784 .960784 .862745 rg n 204 36 12 12 re f* .960784 .960784 .862745 rg n 0 24 18 12 re f* .960784 .960784 .862745 rg n 48 24 30 12 re f* .960784 .960784 .862745 rg n 78 24 6 12 re f* .960784 .960784 .862745 rg n 84 24 36 12 re f* .960784 .960784 .862745 rg n 120 24 6 12 re f* .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 48 12 30 12 re f* .960784 .960784 .862745 rg n 0 0 18 12 re f* .960784 .960784 .862745 rg n 48 0 30 12 re f* .960784 .960784 .862745 rg n 78 0 6 12 re f* .960784 .960784 .862745 rg n 84 0 30 12 re f* .960784 .960784 .862745 rg n 114 0 6 12 re f* BT 1 0 0 1 0 62 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (from) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 0 1 rg (contextlib) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (import) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (contextmanager) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj .666667 .133333 1 rg (@contextmanager) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (before_after) Tj 0 0 0 rg (\() Tj 0 0 0 rg (before) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (after) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (before) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (yield) Tj /F3 10 Tf 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (after) Tj 0 0 0 rg (\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 234.4236 cm q BT 1 0 0 1 0 14 Tm .150888 Tw 12 TL /F1 10 Tf 0 0 0 rg (then ) Tj /F3 10 Tf 0 0 0 rg (before_after ) Tj /F1 10 Tf 0 0 0 rg (is a factory function returning ) Tj /F3 10 Tf 0 0 0 rg (GeneratorContextManager ) Tj /F1 10 Tf 0 0 0 rg (objects which can be) Tj T* 0 Tw (used with the ) Tj /F3 10 Tf 0 0 0 rg (with ) Tj /F1 10 Tf 0 0 0 rg (statement:) Tj T* ET Q Q q 1 0 0 1 62.69291 153.2236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 72 re B* Q q .960784 .960784 .862745 rg n 0 48 6 12 re f* .960784 .960784 .862745 rg n 6 48 6 12 re f* .960784 .960784 .862745 rg n 12 48 6 12 re f* .960784 .960784 .862745 rg n 24 48 24 12 re f* .960784 .960784 .862745 rg n 54 48 72 12 re f* .960784 .960784 .862745 rg n 126 48 6 12 re f* .960784 .960784 .862745 rg n 132 48 48 12 re f* .960784 .960784 .862745 rg n 180 48 6 12 re f* .960784 .960784 .862745 rg n 192 48 42 12 re f* .960784 .960784 .862745 rg n 234 48 12 12 re f* .960784 .960784 .862745 rg n 0 36 18 12 re f* .960784 .960784 .862745 rg n 48 36 30 12 re f* .960784 .960784 .862745 rg n 78 36 6 12 re f* .960784 .960784 .862745 rg n 84 36 42 12 re f* .960784 .960784 .862745 rg n 126 36 6 12 re f* .960784 .960784 .862745 rg n 0 24 36 12 re f* .960784 .960784 .862745 rg n 0 12 30 12 re f* .960784 .960784 .862745 rg n 0 0 30 12 re f* BT 1 0 0 1 0 50 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (with) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (before_after) Tj 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ('BEFORE') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('AFTER') Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ('hello') Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* 0 0 0 rg (BEFORE) Tj 0 0 0 rg T* 0 0 0 rg (hello) Tj 0 0 0 rg T* 0 0 0 rg (AFTER) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 109.2236 cm q BT 1 0 0 1 0 26 Tm .462488 Tw 12 TL /F1 10 Tf 0 0 0 rg (Basically, it is as if the content of the ) Tj /F3 10 Tf 0 0 0 rg (with ) Tj /F1 10 Tf 0 0 0 rg (block was executed in the place of the ) Tj /F3 10 Tf 0 0 0 rg (yield ) Tj /F1 10 Tf 0 0 0 rg (expression in) Tj T* 0 Tw 2.691797 Tw (the generator function. In Python 3.2 ) Tj /F3 10 Tf 0 0 0 rg (GeneratorContextManager ) Tj /F1 10 Tf 0 0 0 rg (objects were enhanced with a) Tj T* 0 Tw /F3 10 Tf 0 0 0 rg (__call__ ) Tj /F1 10 Tf 0 0 0 rg (method, so that they can be used as decorators as in this example:) Tj T* ET Q Q endstream endobj 113 0 obj << /Length 14479 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 655.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 108 re B* Q q .960784 .960784 .862745 rg n 0 84 6 12 re f* .960784 .960784 .862745 rg n 6 84 6 12 re f* .960784 .960784 .862745 rg n 12 84 6 12 re f* .960784 .960784 .862745 rg n 24 84 18 12 re f* .960784 .960784 .862745 rg n 0 72 18 12 re f* .960784 .960784 .862745 rg n 24 72 18 12 re f* .960784 .960784 .862745 rg n 48 72 30 12 re f* .960784 .960784 .862745 rg n 78 72 18 12 re f* .960784 .960784 .862745 rg n 0 60 18 12 re f* .960784 .960784 .862745 rg n 48 60 30 12 re f* .960784 .960784 .862745 rg n 78 60 6 12 re f* .960784 .960784 .862745 rg n 84 60 42 12 re f* .960784 .960784 .862745 rg n 126 60 6 12 re f* .960784 .960784 .862745 rg n 0 48 18 12 re f* .960784 .960784 .862745 rg n 0 36 6 12 re f* .960784 .960784 .862745 rg n 6 36 6 12 re f* .960784 .960784 .862745 rg n 12 36 6 12 re f* .960784 .960784 .862745 rg n 24 36 30 12 re f* .960784 .960784 .862745 rg n 54 36 12 12 re f* .960784 .960784 .862745 rg n 0 24 36 12 re f* .960784 .960784 .862745 rg n 0 12 30 12 re f* .960784 .960784 .862745 rg n 0 0 30 12 re f* BT 1 0 0 1 0 86 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj .666667 .133333 1 rg (@ba) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (hello) Tj 0 0 0 rg (\(\):) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ('hello') Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (hello) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg T* 0 0 0 rg (BEFORE) Tj 0 0 0 rg T* 0 0 0 rg (hello) Tj 0 0 0 rg T* 0 0 0 rg (AFTER) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 515.8236 cm q BT 1 0 0 1 0 122 Tm .20561 Tw 12 TL /F1 10 Tf 0 0 0 rg (The ) Tj /F3 10 Tf 0 0 0 rg (ba ) Tj /F1 10 Tf 0 0 0 rg (decorator is basically inserting a ) Tj /F3 10 Tf 0 0 0 rg (with) Tj ( ) Tj (ba: ) Tj /F1 10 Tf 0 0 0 rg (block inside the function. However there two issues:) Tj T* 0 Tw 1.402126 Tw (the first is that ) Tj /F3 10 Tf 0 0 0 rg (GeneratorContextManager ) Tj /F1 10 Tf 0 0 0 rg (objects are callable only in Python 3.2, so the previous) Tj T* 0 Tw 2.323984 Tw (example will break in older versions of Python \(you can solve this by installing ) Tj /F3 10 Tf 0 0 0 rg (contextlib2) Tj /F1 10 Tf 0 0 0 rg (\); the) Tj T* 0 Tw 1.819147 Tw (second is that ) Tj /F3 10 Tf 0 0 0 rg (GeneratorContextManager ) Tj /F1 10 Tf 0 0 0 rg (objects do not preserve the signature of the decorated) Tj T* 0 Tw 13.76298 Tw (functions: the decorated ) Tj /F3 10 Tf 0 0 0 rg (hello ) Tj /F1 10 Tf 0 0 0 rg (function here will have a generic signature) Tj T* 0 Tw 2.777674 Tw /F3 10 Tf 0 0 0 rg (hello\(*args,) Tj ( ) Tj (**kwargs\) ) Tj /F1 10 Tf 0 0 0 rg (but will break when called with more than zero arguments. For such) Tj T* 0 Tw 3.697976 Tw (reasons the decorator module, starting with release 3.4, offers a ) Tj /F3 10 Tf 0 0 0 rg (decorator.contextmanager) Tj T* 0 Tw .70936 Tw /F1 10 Tf 0 0 0 rg (decorator that solves both problems and works in all supported Python versions. The usage is the same) Tj T* 0 Tw 11.01622 Tw (and factories decorated with ) Tj /F3 10 Tf 0 0 0 rg (decorator.contextmanager ) Tj /F1 10 Tf 0 0 0 rg (will returns instances of) Tj T* 0 Tw 4.152823 Tw /F3 10 Tf 0 0 0 rg (ContextManager) Tj /F1 10 Tf 0 0 0 rg (, a subclass of ) Tj /F3 10 Tf 0 0 0 rg (contextlib.GeneratorContextManager ) Tj /F1 10 Tf 0 0 0 rg (with a ) Tj /F3 10 Tf 0 0 0 rg (__call__) Tj T* 0 Tw /F1 10 Tf 0 0 0 rg (method acting as a signature-preserving decorator.) Tj T* ET Q Q q 1 0 0 1 62.69291 482.8236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (The ) Tj /F3 17.5 Tf 0 0 0 rg (FunctionMaker ) Tj /F2 17.5 Tf 0 0 0 rg (class) Tj T* ET Q Q q 1 0 0 1 62.69291 416.8236 cm q BT 1 0 0 1 0 50 Tm 2.241412 Tw 12 TL /F1 10 Tf 0 0 0 rg (You may wonder about how the functionality of the ) Tj /F3 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf 0 0 0 rg (module is implemented. The basic) Tj T* 0 Tw 1.545868 Tw (building block is a ) Tj /F3 10 Tf 0 0 0 rg (FunctionMaker ) Tj /F1 10 Tf 0 0 0 rg (class which is able to generate on the fly functions with a given) Tj T* 0 Tw .047485 Tw (name and signature from a function template passed as a string. Generally speaking, you should not need) Tj T* 0 Tw 1.164983 Tw (to resort to ) Tj /F3 10 Tf 0 0 0 rg (FunctionMaker ) Tj /F1 10 Tf 0 0 0 rg (when writing ordinary decorators, but it is handy in some circumstances.) Tj T* 0 Tw (You will see an example shortly, in the implementation of a cool decorator utility \() Tj /F3 10 Tf 0 0 0 rg (decorator_apply) Tj /F1 10 Tf 0 0 0 rg (\).) Tj T* ET Q Q q 1 0 0 1 62.69291 374.8236 cm q BT 1 0 0 1 0 26 Tm .414597 Tw 12 TL /F3 10 Tf 0 0 0 rg (FunctionMaker ) Tj /F1 10 Tf 0 0 0 rg (provides a ) Tj /F3 10 Tf 0 0 0 rg (.create ) Tj /F1 10 Tf 0 0 0 rg (classmethod which takes as input the name, signature, and body) Tj T* 0 Tw .305868 Tw (of the function we want to generate as well as the execution environment where the function is generated) Tj T* 0 Tw (by ) Tj /F3 10 Tf 0 0 0 rg (exec) Tj /F1 10 Tf 0 0 0 rg (. Here is an example:) Tj T* ET Q Q q 1 0 0 1 62.69291 281.6236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 84 re B* Q q .960784 .960784 .862745 rg n 0 60 6 12 re f* .960784 .960784 .862745 rg n 6 60 6 12 re f* .960784 .960784 .862745 rg n 12 60 6 12 re f* .960784 .960784 .862745 rg n 24 60 18 12 re f* .960784 .960784 .862745 rg n 48 60 6 12 re f* .960784 .960784 .862745 rg n 54 60 6 12 re f* .960784 .960784 .862745 rg n 60 60 6 12 re f* .960784 .960784 .862745 rg n 66 60 24 12 re f* .960784 .960784 .862745 rg n 90 60 6 12 re f* .960784 .960784 .862745 rg n 102 60 12 12 re f* .960784 .960784 .862745 rg n 114 60 12 12 re f* .960784 .960784 .862745 rg n 126 60 12 12 re f* .960784 .960784 .862745 rg n 144 60 222 12 re f* .960784 .960784 .862745 rg n 0 48 18 12 re f* .960784 .960784 .862745 rg n 48 48 30 12 re f* .960784 .960784 .862745 rg n 78 48 6 12 re f* .960784 .960784 .862745 rg n 84 48 24 12 re f* .960784 .960784 .862745 rg n 108 48 6 12 re f* .960784 .960784 .862745 rg n 120 48 12 12 re f* .960784 .960784 .862745 rg n 132 48 6 12 re f* .960784 .960784 .862745 rg n 0 24 6 12 re f* .960784 .960784 .862745 rg n 6 24 6 12 re f* .960784 .960784 .862745 rg n 12 24 6 12 re f* .960784 .960784 .862745 rg n 24 24 12 12 re f* .960784 .960784 .862745 rg n 42 24 6 12 re f* .960784 .960784 .862745 rg n 54 24 78 12 re f* .960784 .960784 .862745 rg n 132 24 6 12 re f* .960784 .960784 .862745 rg n 138 24 36 12 re f* .960784 .960784 .862745 rg n 174 24 6 12 re f* .960784 .960784 .862745 rg n 180 24 60 12 re f* .960784 .960784 .862745 rg n 240 24 6 12 re f* .960784 .960784 .862745 rg n 252 24 54 12 re f* .960784 .960784 .862745 rg n 306 24 6 12 re f* .960784 .960784 .862745 rg n 318 24 24 12 re f* .960784 .960784 .862745 rg n 342 24 6 12 re f* .960784 .960784 .862745 rg n 348 24 6 12 re f* .960784 .960784 .862745 rg n 354 24 6 12 re f* .960784 .960784 .862745 rg n 360 24 6 12 re f* .960784 .960784 .862745 rg n 366 24 12 12 re f* .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 12 12 re f* .960784 .960784 .862745 rg n 36 12 6 12 re f* .960784 .960784 .862745 rg n 42 12 6 12 re f* .960784 .960784 .862745 rg n 48 12 6 12 re f* .960784 .960784 .862745 rg n 54 12 6 12 re f* .960784 .960784 .862745 rg n 60 12 6 12 re f* .960784 .960784 .862745 rg n 0 0 6 12 re f* .960784 .960784 .862745 rg n 6 0 6 12 re f* .960784 .960784 .862745 rg n 12 0 6 12 re f* .960784 .960784 .862745 rg n 24 0 6 12 re f* .960784 .960784 .862745 rg n 30 0 6 12 re f* .960784 .960784 .862745 rg n 42 0 12 12 re f* BT 1 0 0 1 0 62 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (f) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\):) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# a function with a generic signature) Tj /F3 10 Tf 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f1) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (FunctionMaker) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (create) Tj 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ('f1\(a, b\)') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('f\(a, b\)') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (dict) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (f) Tj 0 0 0 rg (\)\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f1) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (,) Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* 0 0 0 rg (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj 0 0 0 rg ({}) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 249.6236 cm q BT 1 0 0 1 0 14 Tm .226654 Tw 12 TL /F1 10 Tf 0 0 0 rg (It is important to notice that the function body is interpolated before being executed, so be careful with the) Tj T* 0 Tw /F3 10 Tf 0 0 0 rg (% ) Tj /F1 10 Tf 0 0 0 rg (sign!) Tj T* ET Q Q q 1 0 0 1 62.69291 207.6236 cm q BT 1 0 0 1 0 26 Tm 1.995433 Tw 12 TL /F3 10 Tf 0 0 0 rg (FunctionMaker.create ) Tj /F1 10 Tf 0 0 0 rg (also accepts keyword arguments and such arguments are attached to the) Tj T* 0 Tw 1.64686 Tw (resulting function. This is useful if you want to set some function attributes, for instance the docstring) Tj T* 0 Tw /F3 10 Tf 0 0 0 rg (__doc__) Tj /F1 10 Tf 0 0 0 rg (.) Tj T* ET Q Q q 1 0 0 1 62.69291 165.6236 cm q BT 1 0 0 1 0 26 Tm .605318 Tw 12 TL /F1 10 Tf 0 0 0 rg (For debugging/introspection purposes it may be useful to see the source code of the generated function;) Tj T* 0 Tw 2.246235 Tw (to do that, just pass the flag ) Tj /F3 10 Tf 0 0 0 rg (addsource=True ) Tj /F1 10 Tf 0 0 0 rg (and a ) Tj /F3 10 Tf 0 0 0 rg (__source__ ) Tj /F1 10 Tf 0 0 0 rg (attribute will be added to the) Tj T* 0 Tw (generated function:) Tj T* ET Q Q q 1 0 0 1 62.69291 84.42362 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 72 re B* Q q .960784 .960784 .862745 rg n 0 48 6 12 re f* .960784 .960784 .862745 rg n 6 48 6 12 re f* .960784 .960784 .862745 rg n 12 48 6 12 re f* .960784 .960784 .862745 rg n 24 48 12 12 re f* .960784 .960784 .862745 rg n 42 48 6 12 re f* .960784 .960784 .862745 rg n 54 48 78 12 re f* .960784 .960784 .862745 rg n 132 48 6 12 re f* .960784 .960784 .862745 rg n 138 48 36 12 re f* .960784 .960784 .862745 rg n 174 48 6 12 re f* .960784 .960784 .862745 rg n 0 36 18 12 re f* .960784 .960784 .862745 rg n 48 36 60 12 re f* .960784 .960784 .862745 rg n 108 36 6 12 re f* .960784 .960784 .862745 rg n 120 36 54 12 re f* .960784 .960784 .862745 rg n 174 36 6 12 re f* .960784 .960784 .862745 rg n 186 36 24 12 re f* .960784 .960784 .862745 rg n 210 36 6 12 re f* .960784 .960784 .862745 rg n 216 36 6 12 re f* .960784 .960784 .862745 rg n 222 36 6 12 re f* .960784 .960784 .862745 rg n 228 36 6 12 re f* .960784 .960784 .862745 rg n 234 36 12 12 re f* .960784 .960784 .862745 rg n 252 36 54 12 re f* .960784 .960784 .862745 rg n 306 36 6 12 re f* .960784 .960784 .862745 rg n 312 36 24 12 re f* .960784 .960784 .862745 rg n 336 36 6 12 re f* .960784 .960784 .862745 rg n 0 24 6 12 re f* .960784 .960784 .862745 rg n 6 24 6 12 re f* .960784 .960784 .862745 rg n 12 24 6 12 re f* .960784 .960784 .862745 rg n 24 24 30 12 re f* .960784 .960784 .862745 rg n 54 24 6 12 re f* .960784 .960784 .862745 rg n 60 24 12 12 re f* .960784 .960784 .862745 rg n 72 24 6 12 re f* .960784 .960784 .862745 rg n 78 24 60 12 re f* .960784 .960784 .862745 rg n 138 24 6 12 re f* .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 24 12 12 12 re f* .960784 .960784 .862745 rg n 36 12 6 12 re f* .960784 .960784 .862745 rg n 42 12 6 12 re f* .960784 .960784 .862745 rg n 48 12 6 12 re f* .960784 .960784 .862745 rg n 60 12 6 12 re f* .960784 .960784 .862745 rg n 66 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 6 12 re f* .960784 .960784 .862745 rg n 30 0 6 12 re f* .960784 .960784 .862745 rg n 36 0 6 12 re f* .960784 .960784 .862745 rg n 42 0 6 12 re f* .960784 .960784 .862745 rg n 54 0 6 12 re f* .960784 .960784 .862745 rg n 60 0 6 12 re f* BT 1 0 0 1 0 50 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f1) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (FunctionMaker) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (create) Tj 0 0 0 rg (\() Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('f1\(a, b\)') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('f\(a, b\)') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (dict) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (f) Tj 0 0 0 rg (\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (addsource) Tj .4 .4 .4 rg (=) Tj 0 .501961 0 rg (True) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (f1) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__source__) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (f1) Tj 0 0 0 rg (\() Tj 0 0 0 rg (a) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (b) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (f) Tj 0 0 0 rg (\() Tj 0 0 0 rg (a) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (b) Tj 0 0 0 rg (\)) Tj T* ET Q Q Q Q Q endstream endobj 114 0 obj << /Length 18672 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 633.0236 cm q BT 1 0 0 1 0 122 Tm .870651 Tw 12 TL /F3 10 Tf 0 0 0 rg (FunctionMaker.create ) Tj /F1 10 Tf 0 0 0 rg (can take as first argument a string, as in the examples before, or a function.) Tj T* 0 Tw .224985 Tw (This is the most common usage, since typically you want to decorate a pre-existing function. A framework) Tj T* 0 Tw 1.606136 Tw (author may want to use directly ) Tj /F3 10 Tf 0 0 0 rg (FunctionMaker.create ) Tj /F1 10 Tf 0 0 0 rg (instead of ) Tj /F3 10 Tf 0 0 0 rg (decorator) Tj /F1 10 Tf 0 0 0 rg (, since it gives you) Tj T* 0 Tw 1.36686 Tw (direct access to the body of the generated function. For instance, suppose you want to instrument the) Tj T* 0 Tw .372209 Tw /F3 10 Tf 0 0 0 rg (__init__ ) Tj /F1 10 Tf 0 0 0 rg (methods of a set of classes, by preserving their signature \(such use case is not made up; this) Tj T* 0 Tw .673828 Tw (is done in SQAlchemy and in other frameworks\). When the first argument of ) Tj /F3 10 Tf 0 0 0 rg (FunctionMaker.create) Tj T* 0 Tw 3.405814 Tw /F1 10 Tf 0 0 0 rg (is a function, a ) Tj /F3 10 Tf 0 0 0 rg (FunctionMaker ) Tj /F1 10 Tf 0 0 0 rg (object is instantiated internally, with attributes ) Tj /F3 10 Tf 0 0 0 rg (args) Tj /F1 10 Tf 0 0 0 rg (, ) Tj /F3 10 Tf 0 0 0 rg (varargs) Tj /F1 10 Tf 0 0 0 rg (,) Tj T* 0 Tw 5.509982 Tw /F3 10 Tf 0 0 0 rg (keywords ) Tj /F1 10 Tf 0 0 0 rg (and ) Tj /F3 10 Tf 0 0 0 rg (defaults ) Tj /F1 10 Tf 0 0 0 rg (which are the the return values of the standard library function) Tj T* 0 Tw .561318 Tw /F3 10 Tf 0 0 0 rg (inspect.getargspec) Tj /F1 10 Tf 0 0 0 rg (. For each argument in the ) Tj /F3 10 Tf 0 0 0 rg (args ) Tj /F1 10 Tf 0 0 0 rg (\(which is a list of strings containing the names) Tj T* 0 Tw 1.599985 Tw (of the mandatory arguments\) an attribute ) Tj /F3 10 Tf 0 0 0 rg (arg0) Tj /F1 10 Tf 0 0 0 rg (, ) Tj /F3 10 Tf 0 0 0 rg (arg1) Tj /F1 10 Tf 0 0 0 rg (, ..., ) Tj /F3 10 Tf 0 0 0 rg (argN ) Tj /F1 10 Tf 0 0 0 rg (is also generated. Finally, there is a) Tj T* 0 Tw /F3 10 Tf 0 0 0 rg (signature ) Tj /F1 10 Tf 0 0 0 rg (attribute, a string with the signature of the original function.) Tj T* ET Q Q q 1 0 0 1 62.69291 603.0236 cm q BT 1 0 0 1 0 14 Tm 6.828314 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice: you should not pass signature strings with default arguments, i.e. something like) Tj T* 0 Tw /F3 10 Tf 0 0 0 rg ('f1\(a,) Tj ( ) Tj (b=None\)') Tj /F1 10 Tf 0 0 0 rg (. Just pass ) Tj /F3 10 Tf 0 0 0 rg ('f1\(a,) Tj ( ) Tj (b\)' ) Tj /F1 10 Tf 0 0 0 rg (and then a tuple of defaults:) Tj T* ET Q Q q 1 0 0 1 62.69291 533.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 60 re B* Q q .960784 .960784 .862745 rg n 0 36 6 12 re f* .960784 .960784 .862745 rg n 6 36 6 12 re f* .960784 .960784 .862745 rg n 12 36 6 12 re f* .960784 .960784 .862745 rg n 24 36 12 12 re f* .960784 .960784 .862745 rg n 42 36 6 12 re f* .960784 .960784 .862745 rg n 54 36 78 12 re f* .960784 .960784 .862745 rg n 132 36 6 12 re f* .960784 .960784 .862745 rg n 138 36 36 12 re f* .960784 .960784 .862745 rg n 174 36 6 12 re f* .960784 .960784 .862745 rg n 0 24 18 12 re f* .960784 .960784 .862745 rg n 48 24 60 12 re f* .960784 .960784 .862745 rg n 108 24 6 12 re f* .960784 .960784 .862745 rg n 120 24 54 12 re f* .960784 .960784 .862745 rg n 174 24 6 12 re f* .960784 .960784 .862745 rg n 186 24 24 12 re f* .960784 .960784 .862745 rg n 210 24 6 12 re f* .960784 .960784 .862745 rg n 216 24 6 12 re f* .960784 .960784 .862745 rg n 222 24 6 12 re f* .960784 .960784 .862745 rg n 228 24 6 12 re f* .960784 .960784 .862745 rg n 234 24 12 12 re f* .960784 .960784 .862745 rg n 252 24 54 12 re f* .960784 .960784 .862745 rg n 306 24 6 12 re f* .960784 .960784 .862745 rg n 312 24 24 12 re f* .960784 .960784 .862745 rg n 336 24 6 12 re f* .960784 .960784 .862745 rg n 348 24 48 12 re f* .960784 .960784 .862745 rg n 396 24 6 12 re f* .960784 .960784 .862745 rg n 402 24 6 12 re f* .960784 .960784 .862745 rg n 408 24 24 12 re f* .960784 .960784 .862745 rg n 432 24 18 12 re f* .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 30 12 re f* .960784 .960784 .862745 rg n 54 12 6 12 re f* .960784 .960784 .862745 rg n 60 12 60 12 re f* .960784 .960784 .862745 rg n 120 12 6 12 re f* .960784 .960784 .862745 rg n 126 12 12 12 re f* .960784 .960784 .862745 rg n 138 12 12 12 re f* .960784 .960784 .862745 rg n 0 0 42 12 re f* .960784 .960784 .862745 rg n 42 0 6 12 re f* .960784 .960784 .862745 rg n 48 0 24 12 re f* .960784 .960784 .862745 rg n 72 0 6 12 re f* .960784 .960784 .862745 rg n 78 0 6 12 re f* .960784 .960784 .862745 rg n 84 0 18 12 re f* .960784 .960784 .862745 rg n 102 0 6 12 re f* .960784 .960784 .862745 rg n 114 0 18 12 re f* .960784 .960784 .862745 rg n 132 0 12 12 re f* .960784 .960784 .862745 rg n 150 0 42 12 re f* .960784 .960784 .862745 rg n 192 0 6 12 re f* .960784 .960784 .862745 rg n 198 0 24 12 re f* .960784 .960784 .862745 rg n 222 0 6 12 re f* .960784 .960784 .862745 rg n 234 0 30 12 re f* .960784 .960784 .862745 rg n 264 0 6 12 re f* .960784 .960784 .862745 rg n 270 0 24 12 re f* .960784 .960784 .862745 rg n 294 0 6 12 re f* .960784 .960784 .862745 rg n 306 0 48 12 re f* .960784 .960784 .862745 rg n 354 0 6 12 re f* .960784 .960784 .862745 rg n 360 0 6 12 re f* .960784 .960784 .862745 rg n 366 0 24 12 re f* .960784 .960784 .862745 rg n 390 0 18 12 re f* BT 1 0 0 1 0 38 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f1) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (FunctionMaker) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (create) Tj 0 0 0 rg (\() Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('f1\(a, b\)') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('f\(a, b\)') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (dict) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (f) Tj 0 0 0 rg (\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (addsource) Tj .4 .4 .4 rg (=) Tj 0 .501961 0 rg (True) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (defaults) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (\() Tj 0 .501961 0 rg (None) Tj 0 0 0 rg (,\)\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (getargspec) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f1) Tj 0 0 0 rg (\)\)) Tj 0 0 0 rg T* 0 0 0 rg (ArgSpec) Tj 0 0 0 rg (\() Tj 0 0 0 rg (args) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ([) Tj .729412 .129412 .129412 rg ('a') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('b') Tj 0 0 0 rg (],) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (varargs) Tj .4 .4 .4 rg (=) Tj 0 .501961 0 rg (None) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (varkw) Tj .4 .4 .4 rg (=) Tj 0 .501961 0 rg (None) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (defaults) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (\() Tj 0 .501961 0 rg (None) Tj 0 0 0 rg (,\)\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 500.8236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Getting the source code) Tj T* ET Q Q q 1 0 0 1 62.69291 422.8236 cm q BT 1 0 0 1 0 62 Tm 5.045529 Tw 12 TL /F1 10 Tf 0 0 0 rg (Internally ) Tj /F3 10 Tf 0 0 0 rg (FunctionMaker.create ) Tj /F1 10 Tf 0 0 0 rg (uses ) Tj /F3 10 Tf 0 0 0 rg (exec ) Tj /F1 10 Tf 0 0 0 rg (to generate the decorated function. Therefore) Tj T* 0 Tw 2.522126 Tw /F3 10 Tf 0 0 0 rg (inspect.getsource ) Tj /F1 10 Tf 0 0 0 rg (will not work for decorated functions. That means that the usual ) Tj /F3 10 Tf 0 0 0 rg (?? ) Tj /F1 10 Tf 0 0 0 rg (trick in) Tj T* 0 Tw 26.45775 Tw (IPython will give you the \(right on the spot\) message) Tj T* 0 Tw .261647 Tw /F3 10 Tf 0 0 0 rg (Dynamically) Tj ( ) Tj (generated) Tj ( ) Tj (function.) Tj ( ) Tj (No) Tj ( ) Tj (source) Tj ( ) Tj (code available) Tj /F1 10 Tf 0 0 0 rg (. In the past I have considered) Tj T* 0 Tw .945366 Tw (this acceptable, since ) Tj /F3 10 Tf 0 0 0 rg (inspect.getsource ) Tj /F1 10 Tf 0 0 0 rg (does not really work even with regular decorators. In that) Tj T* 0 Tw (case ) Tj /F3 10 Tf 0 0 0 rg (inspect.getsource ) Tj /F1 10 Tf 0 0 0 rg (gives you the wrapper source code which is probably not what you want:) Tj T* ET Q Q q 1 0 0 1 62.69291 353.6236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 60 re B* Q q .960784 .960784 .862745 rg n 0 36 18 12 re f* .960784 .960784 .862745 rg n 24 36 72 12 re f* .960784 .960784 .862745 rg n 96 36 6 12 re f* .960784 .960784 .862745 rg n 102 36 24 12 re f* .960784 .960784 .862745 rg n 126 36 12 12 re f* .960784 .960784 .862745 rg n 24 24 18 12 re f* .960784 .960784 .862745 rg n 48 24 42 12 re f* .960784 .960784 .862745 rg n 90 24 6 12 re f* .960784 .960784 .862745 rg n 96 24 6 12 re f* .960784 .960784 .862745 rg n 102 24 24 12 re f* .960784 .960784 .862745 rg n 126 24 6 12 re f* .960784 .960784 .862745 rg n 138 24 12 12 re f* .960784 .960784 .862745 rg n 150 24 12 12 re f* .960784 .960784 .862745 rg n 162 24 12 12 re f* .960784 .960784 .862745 rg n 48 12 36 12 re f* .960784 .960784 .862745 rg n 90 12 24 12 re f* .960784 .960784 .862745 rg n 114 12 6 12 re f* .960784 .960784 .862745 rg n 120 12 6 12 re f* .960784 .960784 .862745 rg n 126 12 24 12 re f* .960784 .960784 .862745 rg n 150 12 6 12 re f* .960784 .960784 .862745 rg n 162 12 12 12 re f* .960784 .960784 .862745 rg n 174 12 12 12 re f* .960784 .960784 .862745 rg n 186 12 6 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 42 12 re f* BT 1 0 0 1 0 38 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (identity_dec) Tj 0 0 0 rg (\() Tj 0 0 0 rg (func) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (wrapper) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (wrapper) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 308.4236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 24 12 42 12 re f* .960784 .960784 .862745 rg n 66 12 6 12 re f* .960784 .960784 .862745 rg n 72 12 6 12 re f* .960784 .960784 .862745 rg n 78 12 24 12 re f* .960784 .960784 .862745 rg n 102 12 6 12 re f* .960784 .960784 .862745 rg n 114 12 12 12 re f* .960784 .960784 .862745 rg n 126 12 12 12 re f* .960784 .960784 .862745 rg n 138 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 24 12 re f* .960784 .960784 .862745 rg n 90 0 6 12 re f* .960784 .960784 .862745 rg n 96 0 6 12 re f* .960784 .960784 .862745 rg n 102 0 24 12 re f* .960784 .960784 .862745 rg n 126 0 6 12 re f* .960784 .960784 .862745 rg n 138 0 12 12 re f* .960784 .960784 .862745 rg n 150 0 12 12 re f* .960784 .960784 .862745 rg n 162 0 6 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (wrapper) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 227.2236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 72 re B* Q q .960784 .960784 .862745 rg n 0 48 6 12 re f* .960784 .960784 .862745 rg n 6 48 6 12 re f* .960784 .960784 .862745 rg n 12 48 6 12 re f* .960784 .960784 .862745 rg n 24 48 36 12 re f* .960784 .960784 .862745 rg n 66 48 42 12 re f* .960784 .960784 .862745 rg n 0 36 6 12 re f* .960784 .960784 .862745 rg n 6 36 6 12 re f* .960784 .960784 .862745 rg n 12 36 6 12 re f* .960784 .960784 .862745 rg n 24 36 30 12 re f* .960784 .960784 .862745 rg n 54 36 6 12 re f* .960784 .960784 .862745 rg n 60 36 42 12 re f* .960784 .960784 .862745 rg n 102 36 6 12 re f* .960784 .960784 .862745 rg n 108 36 54 12 re f* .960784 .960784 .862745 rg n 162 36 6 12 re f* .960784 .960784 .862745 rg n 168 36 42 12 re f* .960784 .960784 .862745 rg n 210 36 12 12 re f* .960784 .960784 .862745 rg n 24 24 18 12 re f* .960784 .960784 .862745 rg n 48 24 42 12 re f* .960784 .960784 .862745 rg n 90 24 6 12 re f* .960784 .960784 .862745 rg n 96 24 6 12 re f* .960784 .960784 .862745 rg n 102 24 24 12 re f* .960784 .960784 .862745 rg n 126 24 6 12 re f* .960784 .960784 .862745 rg n 138 24 12 12 re f* .960784 .960784 .862745 rg n 150 24 12 12 re f* .960784 .960784 .862745 rg n 162 24 12 12 re f* .960784 .960784 .862745 rg n 48 12 36 12 re f* .960784 .960784 .862745 rg n 90 12 24 12 re f* .960784 .960784 .862745 rg n 114 12 6 12 re f* .960784 .960784 .862745 rg n 120 12 6 12 re f* .960784 .960784 .862745 rg n 126 12 24 12 re f* .960784 .960784 .862745 rg n 150 12 6 12 re f* .960784 .960784 .862745 rg n 162 12 12 12 re f* .960784 .960784 .862745 rg n 174 12 12 12 re f* .960784 .960784 .862745 rg n 186 12 6 12 re f* .960784 .960784 .862745 rg n 0 0 6 12 re f* .960784 .960784 .862745 rg n 6 0 54 12 re f* .960784 .960784 .862745 rg n 60 0 6 12 re f* BT 1 0 0 1 0 50 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (import) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 0 1 rg (inspect) Tj /F3 10 Tf 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (inspect) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (getsource) Tj 0 0 0 rg (\() Tj 0 0 0 rg (example) Tj 0 0 0 rg (\)\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (wrapper) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (<) Tj 0 0 0 rg (BLANKLINE) Tj .4 .4 .4 rg (>) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 171.2236 cm q BT 1 0 0 1 0 38 Tm .011098 Tw 12 TL /F1 10 Tf 0 0 0 rg (\(see bug report ) Tj 0 0 .501961 rg (1764286 ) Tj 0 0 0 rg (for an explanation of what is happening\). Unfortunately the bug is still there, in all) Tj T* 0 Tw 1.33436 Tw (versions of Python except Python 3.5, which is not yet released. There is however a workaround. The) Tj T* 0 Tw .725984 Tw (decorated function has an attribute ) Tj /F3 10 Tf 0 0 0 rg (__wrapped__) Tj /F1 10 Tf 0 0 0 rg (, pointing to the original function. The easy way to get) Tj T* 0 Tw (the source code is to call ) Tj /F3 10 Tf 0 0 0 rg (inspect.getsource ) Tj /F1 10 Tf 0 0 0 rg (on the undecorated function:) Tj T* ET Q Q q 1 0 0 1 62.69291 78.02362 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 84 re B* Q q .960784 .960784 .862745 rg n 0 60 6 12 re f* .960784 .960784 .862745 rg n 6 60 6 12 re f* .960784 .960784 .862745 rg n 12 60 6 12 re f* .960784 .960784 .862745 rg n 24 60 30 12 re f* .960784 .960784 .862745 rg n 54 60 6 12 re f* .960784 .960784 .862745 rg n 60 60 42 12 re f* .960784 .960784 .862745 rg n 102 60 6 12 re f* .960784 .960784 .862745 rg n 108 60 54 12 re f* .960784 .960784 .862745 rg n 162 60 6 12 re f* .960784 .960784 .862745 rg n 168 60 54 12 re f* .960784 .960784 .862745 rg n 222 60 6 12 re f* .960784 .960784 .862745 rg n 228 60 66 12 re f* .960784 .960784 .862745 rg n 294 60 12 12 re f* .960784 .960784 .862745 rg n 0 48 90 12 re f* .960784 .960784 .862745 rg n 0 36 18 12 re f* .960784 .960784 .862745 rg n 24 36 54 12 re f* .960784 .960784 .862745 rg n 78 36 6 12 re f* .960784 .960784 .862745 rg n 84 36 6 12 re f* .960784 .960784 .862745 rg n 90 36 6 12 re f* .960784 .960784 .862745 rg n 102 36 18 12 re f* .960784 .960784 .862745 rg n 120 36 6 12 re f* .960784 .960784 .862745 rg n 126 36 6 12 re f* .960784 .960784 .862745 rg n 132 36 12 12 re f* .960784 .960784 .862745 rg n 24 24 144 12 re f* .960784 .960784 .862745 rg n 24 12 12 12 re f* .960784 .960784 .862745 rg n 42 12 6 12 re f* .960784 .960784 .862745 rg n 54 12 12 12 re f* .960784 .960784 .862745 rg n 72 12 6 12 re f* .960784 .960784 .862745 rg n 78 12 6 12 re f* .960784 .960784 .862745 rg n 48 0 36 12 re f* .960784 .960784 .862745 rg n 90 0 18 12 re f* BT 1 0 0 1 0 62 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (inspect) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (getsource) Tj 0 0 0 rg (\() Tj 0 0 0 rg (factorial) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__wrapped__) Tj 0 0 0 rg (\)\)) Tj 0 0 0 rg T* .666667 .133333 1 rg (@tail_recursive) Tj 0 0 0 rg T* /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (factorial) Tj 0 0 0 rg (\() Tj 0 0 0 rg (n) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (acc) Tj .4 .4 .4 rg (=) Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj .729412 .129412 .129412 rg ("The good old factorial") Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (if) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (n) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (==) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (0) Tj 0 0 0 rg (:) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (acc) Tj 0 0 0 rg T* ET Q Q Q Q Q endstream endobj 115 0 obj << /Length 15316 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 727.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 24 12 36 12 re f* .960784 .960784 .862745 rg n 66 12 54 12 re f* .960784 .960784 .862745 rg n 120 12 6 12 re f* .960784 .960784 .862745 rg n 126 12 6 12 re f* .960784 .960784 .862745 rg n 132 12 6 12 re f* .960784 .960784 .862745 rg n 138 12 6 12 re f* .960784 .960784 .862745 rg n 144 12 6 12 re f* .960784 .960784 .862745 rg n 156 12 6 12 re f* .960784 .960784 .862745 rg n 162 12 6 12 re f* .960784 .960784 .862745 rg n 168 12 18 12 re f* .960784 .960784 .862745 rg n 186 12 6 12 re f* .960784 .960784 .862745 rg n 0 0 6 12 re f* .960784 .960784 .862745 rg n 6 0 54 12 re f* .960784 .960784 .862745 rg n 60 0 6 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (factorial) Tj 0 0 0 rg (\() Tj 0 0 0 rg (n) Tj .4 .4 .4 rg (-) Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (n) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (acc) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (<) Tj 0 0 0 rg (BLANKLINE) Tj .4 .4 .4 rg (>) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 694.8236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Dealing with third party decorators) Tj T* ET Q Q q 1 0 0 1 62.69291 640.8236 cm q BT 1 0 0 1 0 38 Tm .321654 Tw 12 TL /F1 10 Tf 0 0 0 rg (Sometimes you find on the net some cool decorator that you would like to include in your code. However,) Tj T* 0 Tw .50061 Tw (more often than not the cool decorator is not signature-preserving. Therefore you may want an easy way) Tj T* 0 Tw 1.814597 Tw (to upgrade third party decorators to signature-preserving decorators without having to rewrite them in) Tj T* 0 Tw (terms of ) Tj /F3 10 Tf 0 0 0 rg (decorator) Tj /F1 10 Tf 0 0 0 rg (. You can use a ) Tj /F3 10 Tf 0 0 0 rg (FunctionMaker ) Tj /F1 10 Tf 0 0 0 rg (to implement that functionality as follows:) Tj T* ET Q Q q 1 0 0 1 62.69291 523.6236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 108 re B* Q q .960784 .960784 .862745 rg n 0 84 18 12 re f* .960784 .960784 .862745 rg n 24 84 90 12 re f* .960784 .960784 .862745 rg n 114 84 6 12 re f* .960784 .960784 .862745 rg n 120 84 18 12 re f* .960784 .960784 .862745 rg n 138 84 6 12 re f* .960784 .960784 .862745 rg n 150 84 24 12 re f* .960784 .960784 .862745 rg n 174 84 12 12 re f* .960784 .960784 .862745 rg n 24 72 18 12 re f* .960784 .960784 .862745 rg n 0 60 378 12 re f* .960784 .960784 .862745 rg n 0 48 264 12 re f* .960784 .960784 .862745 rg n 0 36 42 12 re f* .960784 .960784 .862745 rg n 24 24 36 12 re f* .960784 .960784 .862745 rg n 66 24 78 12 re f* .960784 .960784 .862745 rg n 144 24 6 12 re f* .960784 .960784 .862745 rg n 150 24 36 12 re f* .960784 .960784 .862745 rg n 186 24 6 12 re f* .960784 .960784 .862745 rg n 48 12 24 12 re f* .960784 .960784 .862745 rg n 72 12 6 12 re f* .960784 .960784 .862745 rg n 84 12 96 12 re f* .960784 .960784 .862745 rg n 180 12 78 12 re f* .960784 .960784 .862745 rg n 258 12 12 12 re f* .960784 .960784 .862745 rg n 270 12 6 12 re f* .960784 .960784 .862745 rg n 48 0 24 12 re f* .960784 .960784 .862745 rg n 72 0 6 12 re f* .960784 .960784 .862745 rg n 78 0 42 12 re f* .960784 .960784 .862745 rg n 120 0 6 12 re f* .960784 .960784 .862745 rg n 126 0 18 12 re f* .960784 .960784 .862745 rg n 144 0 6 12 re f* .960784 .960784 .862745 rg n 150 0 24 12 re f* .960784 .960784 .862745 rg n 174 0 18 12 re f* .960784 .960784 .862745 rg n 198 0 66 12 re f* .960784 .960784 .862745 rg n 264 0 6 12 re f* .960784 .960784 .862745 rg n 270 0 24 12 re f* .960784 .960784 .862745 rg n 294 0 6 12 re f* BT 1 0 0 1 0 86 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (decorator_apply) Tj 0 0 0 rg (\() Tj 0 0 0 rg (dec) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf .729412 .129412 .129412 rg (""") Tj T* ( Decorate a function by preserving the signature even if dec) Tj T* ( is not a signature-preserving decorator.) Tj T* ( """) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (FunctionMaker) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (create) Tj 0 0 0 rg (\() Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (func) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('return decfunc\() Tj /F5 10 Tf .733333 .4 .533333 rg (%\(signature\)s) Tj /F3 10 Tf .729412 .129412 .129412 rg (\)') Tj 0 0 0 rg (,) Tj 0 0 0 rg T* ( ) Tj 0 .501961 0 rg (dict) Tj 0 0 0 rg (\() Tj 0 0 0 rg (decfunc) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (dec) Tj 0 0 0 rg (\() Tj 0 0 0 rg (func) Tj 0 0 0 rg (\)\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (__wrapped__) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (func) Tj 0 0 0 rg (\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 479.6236 cm q BT 1 0 0 1 0 26 Tm .079982 Tw 12 TL /F3 10 Tf 0 0 0 rg (decorator_apply ) Tj /F1 10 Tf 0 0 0 rg (sets the attribute ) Tj /F3 10 Tf 0 0 0 rg (__wrapped__ ) Tj /F1 10 Tf 0 0 0 rg (of the generated function to the original function, so) Tj T* 0 Tw .00856 Tw (that you can get the right source code. If you are using a Python more recent than 3.2, you should also set) Tj T* 0 Tw (the ) Tj /F3 10 Tf 0 0 0 rg (__qualname__ ) Tj /F1 10 Tf 0 0 0 rg (attribute to preserve the qualified name of the original function.) Tj T* ET Q Q q 1 0 0 1 62.69291 437.6236 cm q BT 1 0 0 1 0 26 Tm .13104 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice that I am not providing this functionality in the ) Tj /F3 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf 0 0 0 rg (module directly since I think it is best to) Tj T* 0 Tw 2.070751 Tw (rewrite the decorator rather than adding an additional level of indirection. However, practicality beats) Tj T* 0 Tw (purity, so you can add ) Tj /F3 10 Tf 0 0 0 rg (decorator_apply ) Tj /F1 10 Tf 0 0 0 rg (to your toolbox and use it if you need to.) Tj T* ET Q Q q 1 0 0 1 62.69291 383.6236 cm q BT 1 0 0 1 0 38 Tm 1.74881 Tw 12 TL /F1 10 Tf 0 0 0 rg (In order to give an example of usage of ) Tj /F3 10 Tf 0 0 0 rg (decorator_apply) Tj /F1 10 Tf 0 0 0 rg (, I will show a pretty slick decorator that) Tj T* 0 Tw 1.276651 Tw (converts a tail-recursive function in an iterative function. I have shamelessly stolen the basic idea from) Tj T* 0 Tw 43.62829 Tw (Kay Schluehr's recipe in the Python Cookbook,) Tj T* 0 Tw 0 0 .501961 rg (http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496691) Tj 0 0 0 rg (.) Tj T* ET Q Q q 1 0 0 1 62.69291 86.42362 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 288 re B* Q q .960784 .960784 .862745 rg n 0 264 30 12 re f* .960784 .960784 .862745 rg n 36 264 78 12 re f* .960784 .960784 .862745 rg n 114 264 6 12 re f* .960784 .960784 .862745 rg n 120 264 36 12 re f* .960784 .960784 .862745 rg n 156 264 12 12 re f* .960784 .960784 .862745 rg n 24 252 18 12 re f* .960784 .960784 .862745 rg n 0 240 354 12 re f* .960784 .960784 .862745 rg n 0 228 396 12 re f* .960784 .960784 .862745 rg n 0 216 276 12 re f* .960784 .960784 .862745 rg n 0 204 42 12 re f* .960784 .960784 .862745 rg n 24 180 18 12 re f* .960784 .960784 .862745 rg n 48 180 48 12 re f* .960784 .960784 .862745 rg n 96 180 6 12 re f* .960784 .960784 .862745 rg n 102 180 24 12 re f* .960784 .960784 .862745 rg n 126 180 6 12 re f* .960784 .960784 .862745 rg n 138 180 24 12 re f* .960784 .960784 .862745 rg n 162 180 12 12 re f* .960784 .960784 .862745 rg n 48 168 24 12 re f* .960784 .960784 .862745 rg n 72 168 6 12 re f* .960784 .960784 .862745 rg n 78 168 24 12 re f* .960784 .960784 .862745 rg n 108 168 6 12 re f* .960784 .960784 .862745 rg n 120 168 24 12 re f* .960784 .960784 .862745 rg n 48 156 24 12 re f* .960784 .960784 .862745 rg n 72 156 6 12 re f* .960784 .960784 .862745 rg n 78 156 54 12 re f* .960784 .960784 .862745 rg n 138 156 6 12 re f* .960784 .960784 .862745 rg n 150 156 24 12 re f* .960784 .960784 .862745 rg n 48 144 24 12 re f* .960784 .960784 .862745 rg n 72 144 6 12 re f* .960784 .960784 .862745 rg n 78 144 48 12 re f* .960784 .960784 .862745 rg n 132 144 6 12 re f* .960784 .960784 .862745 rg n 144 144 36 12 re f* .960784 .960784 .862745 rg n 180 144 12 12 re f* .960784 .960784 .862745 rg n 204 144 60 12 re f* .960784 .960784 .862745 rg n 24 120 18 12 re f* .960784 .960784 .862745 rg n 48 120 48 12 re f* .960784 .960784 .862745 rg n 96 120 6 12 re f* .960784 .960784 .862745 rg n 102 120 24 12 re f* .960784 .960784 .862745 rg n 126 120 6 12 re f* .960784 .960784 .862745 rg n 138 120 6 12 re f* .960784 .960784 .862745 rg n 144 120 24 12 re f* .960784 .960784 .862745 rg n 168 120 6 12 re f* .960784 .960784 .862745 rg n 180 120 12 12 re f* .960784 .960784 .862745 rg n 192 120 18 12 re f* .960784 .960784 .862745 rg n 210 120 12 12 re f* .960784 .960784 .862745 rg n 48 108 48 12 re f* .960784 .960784 .862745 rg n 102 108 6 12 re f* .960784 .960784 .862745 rg n 114 108 24 12 re f* .960784 .960784 .862745 rg n 138 108 6 12 re f* .960784 .960784 .862745 rg n 144 108 48 12 re f* .960784 .960784 .862745 rg n 48 96 12 12 re f* .960784 .960784 .862745 rg n 66 96 24 12 re f* .960784 .960784 .862745 rg n 90 96 6 12 re f* .960784 .960784 .862745 rg n 96 96 54 12 re f* .960784 .960784 .862745 rg n 150 96 6 12 re f* .960784 .960784 .862745 rg n 72 84 24 12 re f* .960784 .960784 .862745 rg n 102 84 6 12 re f* .960784 .960784 .862745 rg n 114 84 24 12 re f* .960784 .960784 .862745 rg n 138 84 6 12 re f* .960784 .960784 .862745 rg n 144 84 24 12 re f* .960784 .960784 .862745 rg n 72 72 24 12 re f* .960784 .960784 .862745 rg n 96 72 6 12 re f* .960784 .960784 .862745 rg n 102 72 54 12 re f* .960784 .960784 .862745 rg n 162 72 6 12 re f* .960784 .960784 .862745 rg n 174 72 30 12 re f* .960784 .960784 .862745 rg n 72 60 18 12 re f* .960784 .960784 .862745 rg n 90 60 6 12 re f* .960784 .960784 .862745 rg n 96 48 30 12 re f* .960784 .960784 .862745 rg n 132 48 24 12 re f* .960784 .960784 .862745 rg n 156 48 6 12 re f* .960784 .960784 .862745 rg n 120 36 36 12 re f* .960784 .960784 .862745 rg n 162 36 6 12 re f* .960784 .960784 .862745 rg n 174 36 24 12 re f* .960784 .960784 .862745 rg n 198 36 6 12 re f* .960784 .960784 .862745 rg n 204 36 6 12 re f* .960784 .960784 .862745 rg n 210 36 24 12 re f* .960784 .960784 .862745 rg n 234 36 6 12 re f* .960784 .960784 .862745 rg n 246 36 12 12 re f* .960784 .960784 .862745 rg n 258 36 18 12 re f* .960784 .960784 .862745 rg n 276 36 6 12 re f* .960784 .960784 .862745 rg n 120 24 12 12 re f* .960784 .960784 .862745 rg n 138 24 36 12 re f* .960784 .960784 .862745 rg n 180 24 12 12 re f* .960784 .960784 .862745 rg n 198 24 48 12 re f* .960784 .960784 .862745 rg n 246 24 6 12 re f* .960784 .960784 .862745 rg n 264 24 108 12 re f* .960784 .960784 .862745 rg n 144 12 24 12 re f* .960784 .960784 .862745 rg n 168 12 6 12 re f* .960784 .960784 .862745 rg n 180 12 18 12 re f* .960784 .960784 .862745 rg n 204 12 6 12 re f* .960784 .960784 .862745 rg n 216 12 24 12 re f* .960784 .960784 .862745 rg n 240 12 6 12 re f* .960784 .960784 .862745 rg n 246 12 42 12 re f* .960784 .960784 .862745 rg n 120 0 24 12 re f* .960784 .960784 .862745 rg n 144 0 6 12 re f* .960784 .960784 .862745 rg n 162 0 66 12 re f* BT 1 0 0 1 0 266 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (class) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 0 1 rg (TailRecursive) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf .729412 .129412 .129412 rg (""") Tj T* ( tail_recursive decorator based on Kay Schluehr's recipe) Tj T* ( http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496691) Tj T* ( with improvements by me and George Sakkis.) Tj T* ( """) Tj /F3 10 Tf 0 0 0 rg T* T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (__init__) Tj 0 0 0 rg (\() Tj 0 .501961 0 rg (self) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (func) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj 0 0 0 rg T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (firstcall) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (True) Tj 0 0 0 rg T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (CONTINUE) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# sentinel) Tj /F3 10 Tf 0 0 0 rg T* T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (__call__) Tj 0 0 0 rg (\() Tj 0 .501961 0 rg (self) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kwd) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (CONTINUE) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (CONTINUE) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (if) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (firstcall) Tj 0 0 0 rg (:) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (func) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (func) Tj 0 0 0 rg T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (firstcall) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (False) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (try) Tj /F3 10 Tf 0 0 0 rg (:) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (while) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (True) Tj 0 0 0 rg (:) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (result) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kwd) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (if) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (result) Tj 0 0 0 rg ( ) Tj /F5 10 Tf .666667 .133333 1 rg (is) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (CONTINUE) Tj 0 0 0 rg (:) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# update arguments) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (kwd) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (argskwd) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (else) Tj /F3 10 Tf 0 0 0 rg (:) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# last call) Tj /F3 10 Tf 0 0 0 rg T* ET Q Q Q Q Q endstream endobj 116 0 obj << /Length 13068 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 679.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 84 re B* Q q .960784 .960784 .862745 rg n 144 60 36 12 re f* .960784 .960784 .862745 rg n 186 60 36 12 re f* .960784 .960784 .862745 rg n 72 48 42 12 re f* .960784 .960784 .862745 rg n 114 48 6 12 re f* .960784 .960784 .862745 rg n 96 36 24 12 re f* .960784 .960784 .862745 rg n 120 36 6 12 re f* .960784 .960784 .862745 rg n 126 36 54 12 re f* .960784 .960784 .862745 rg n 186 36 6 12 re f* .960784 .960784 .862745 rg n 198 36 24 12 re f* .960784 .960784 .862745 rg n 48 24 24 12 re f* .960784 .960784 .862745 rg n 72 24 6 12 re f* .960784 .960784 .862745 rg n 90 24 234 12 re f* .960784 .960784 .862745 rg n 72 12 24 12 re f* .960784 .960784 .862745 rg n 96 12 6 12 re f* .960784 .960784 .862745 rg n 102 12 42 12 re f* .960784 .960784 .862745 rg n 150 12 6 12 re f* .960784 .960784 .862745 rg n 162 12 24 12 re f* .960784 .960784 .862745 rg n 186 12 6 12 re f* .960784 .960784 .862745 rg n 198 12 18 12 re f* .960784 .960784 .862745 rg n 72 0 36 12 re f* .960784 .960784 .862745 rg n 114 0 48 12 re f* BT 1 0 0 1 0 62 Tm 12 TL /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (result) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (finally) Tj /F3 10 Tf 0 0 0 rg (:) Tj 0 0 0 rg T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (firstcall) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (True) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (else) Tj /F3 10 Tf 0 0 0 rg (:) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# return the arguments of the tail call) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (argskwd) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (kwd) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (CONTINUE) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 659.8236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Here the decorator is implemented as a class returning callable objects.) Tj T* ET Q Q q 1 0 0 1 62.69291 614.6236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 24 12 84 12 re f* .960784 .960784 .862745 rg n 108 12 6 12 re f* .960784 .960784 .862745 rg n 114 12 24 12 re f* .960784 .960784 .862745 rg n 138 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 90 12 re f* .960784 .960784 .862745 rg n 156 0 6 12 re f* .960784 .960784 .862745 rg n 162 0 78 12 re f* .960784 .960784 .862745 rg n 240 0 6 12 re f* .960784 .960784 .862745 rg n 252 0 24 12 re f* .960784 .960784 .862745 rg n 276 0 6 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (tail_recursive) Tj 0 0 0 rg (\() Tj 0 0 0 rg (func) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (decorator_apply) Tj 0 0 0 rg (\() Tj 0 0 0 rg (TailRecursive) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj 0 0 0 rg (\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 594.6236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Here is how you apply the upgraded decorator to the good old factorial:) Tj T* ET Q Q q 1 0 0 1 62.69291 501.4236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 84 re B* Q q .960784 .960784 .862745 rg n 0 60 90 12 re f* .960784 .960784 .862745 rg n 0 48 18 12 re f* .960784 .960784 .862745 rg n 24 48 54 12 re f* .960784 .960784 .862745 rg n 78 48 6 12 re f* .960784 .960784 .862745 rg n 84 48 6 12 re f* .960784 .960784 .862745 rg n 90 48 6 12 re f* .960784 .960784 .862745 rg n 102 48 18 12 re f* .960784 .960784 .862745 rg n 120 48 6 12 re f* .960784 .960784 .862745 rg n 126 48 6 12 re f* .960784 .960784 .862745 rg n 132 48 12 12 re f* .960784 .960784 .862745 rg n 24 36 144 12 re f* .960784 .960784 .862745 rg n 24 24 12 12 re f* .960784 .960784 .862745 rg n 42 24 6 12 re f* .960784 .960784 .862745 rg n 54 24 12 12 re f* .960784 .960784 .862745 rg n 72 24 6 12 re f* .960784 .960784 .862745 rg n 78 24 6 12 re f* .960784 .960784 .862745 rg n 48 12 36 12 re f* .960784 .960784 .862745 rg n 90 12 18 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 54 12 re f* .960784 .960784 .862745 rg n 120 0 6 12 re f* .960784 .960784 .862745 rg n 126 0 6 12 re f* .960784 .960784 .862745 rg n 132 0 6 12 re f* .960784 .960784 .862745 rg n 138 0 6 12 re f* .960784 .960784 .862745 rg n 144 0 6 12 re f* .960784 .960784 .862745 rg n 156 0 6 12 re f* .960784 .960784 .862745 rg n 162 0 6 12 re f* .960784 .960784 .862745 rg n 168 0 18 12 re f* .960784 .960784 .862745 rg n 186 0 6 12 re f* BT 1 0 0 1 0 62 Tm 12 TL /F3 10 Tf .666667 .133333 1 rg (@tail_recursive) Tj 0 0 0 rg T* /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (factorial) Tj 0 0 0 rg (\() Tj 0 0 0 rg (n) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (acc) Tj .4 .4 .4 rg (=) Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj .729412 .129412 .129412 rg ("The good old factorial") Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (if) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (n) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (==) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (0) Tj 0 0 0 rg (:) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (acc) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (factorial) Tj 0 0 0 rg (\() Tj 0 0 0 rg (n) Tj .4 .4 .4 rg (-) Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (n) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (acc) Tj 0 0 0 rg (\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 456.2236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 30 12 re f* .960784 .960784 .862745 rg n 54 12 6 12 re f* .960784 .960784 .862745 rg n 60 12 54 12 re f* .960784 .960784 .862745 rg n 114 12 6 12 re f* .960784 .960784 .862745 rg n 120 12 6 12 re f* .960784 .960784 .862745 rg n 126 12 12 12 re f* .960784 .960784 .862745 rg n 0 0 12 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (factorial) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (4) Tj 0 0 0 rg (\)\)) Tj 0 0 0 rg T* .4 .4 .4 rg (24) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 400.2236 cm q BT 1 0 0 1 0 38 Tm .188935 Tw 12 TL /F1 10 Tf 0 0 0 rg (This decorator is pretty impressive, and should give you some food for your mind ;\) Notice that there is no) Tj T* 0 Tw 1.339983 Tw (recursion limit now, and you can easily compute ) Tj /F3 10 Tf 0 0 0 rg (factorial\(1001\) ) Tj /F1 10 Tf 0 0 0 rg (or larger without filling the stack) Tj T* 0 Tw .909431 Tw (frame. Notice also that the decorator will not work on functions which are not tail recursive, such as the) Tj T* 0 Tw (following) Tj T* ET Q Q q 1 0 0 1 62.69291 331.0236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 60 re B* Q q .960784 .960784 .862745 rg n 0 36 18 12 re f* .960784 .960784 .862745 rg n 24 36 24 12 re f* .960784 .960784 .862745 rg n 48 36 6 12 re f* .960784 .960784 .862745 rg n 54 36 6 12 re f* .960784 .960784 .862745 rg n 60 36 12 12 re f* .960784 .960784 .862745 rg n 84 36 168 12 re f* .960784 .960784 .862745 rg n 24 24 12 12 re f* .960784 .960784 .862745 rg n 42 24 6 12 re f* .960784 .960784 .862745 rg n 54 24 12 12 re f* .960784 .960784 .862745 rg n 72 24 6 12 re f* .960784 .960784 .862745 rg n 78 24 6 12 re f* .960784 .960784 .862745 rg n 48 12 36 12 re f* .960784 .960784 .862745 rg n 90 12 6 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 6 12 re f* .960784 .960784 .862745 rg n 78 0 6 12 re f* .960784 .960784 .862745 rg n 90 0 24 12 re f* .960784 .960784 .862745 rg n 114 0 6 12 re f* .960784 .960784 .862745 rg n 120 0 6 12 re f* .960784 .960784 .862745 rg n 126 0 6 12 re f* .960784 .960784 .862745 rg n 132 0 6 12 re f* .960784 .960784 .862745 rg n 138 0 6 12 re f* BT 1 0 0 1 0 38 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (fact) Tj 0 0 0 rg (\() Tj 0 0 0 rg (n) Tj 0 0 0 rg (\):) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# this is not tail-recursive) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (if) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (n) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (==) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (0) Tj 0 0 0 rg (:) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .4 .4 .4 rg (1) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (n) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (fact) Tj 0 0 0 rg (\() Tj 0 0 0 rg (n) Tj .4 .4 .4 rg (-) Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 299.0236 cm q 0 0 0 rg BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .541098 Tw (\(reminder: a function is tail recursive if it either returns a value without making a recursive call, or returns) Tj T* 0 Tw (directly the result of a recursive call\).) Tj T* ET Q Q q 1 0 0 1 62.69291 266.0236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Multiple dispatch) Tj T* ET Q Q q 1 0 0 1 62.69291 176.0236 cm q BT 1 0 0 1 0 74 Tm .11936 Tw 12 TL /F1 10 Tf 0 0 0 rg (There has been talk of implementing multiple dispatch \(i.e. generic\) functions in Python for over ten years.) Tj T* 0 Tw 1.46332 Tw (Last year for the first time something concrete was done and now in Python 3.4 we have a decorator) Tj T* 0 Tw .294147 Tw /F3 10 Tf 0 0 0 rg (functools.singledispatch ) Tj /F1 10 Tf 0 0 0 rg (which can be used to implement generic functions. As the name implies,) Tj T* 0 Tw .063322 Tw (it has the restriction of being limited to single dispatch, i.e. it is able to dispatch on the first argument of the) Tj T* 0 Tw 1.423555 Tw (function only. The decorator module provide a decorator factory ) Tj /F3 10 Tf 0 0 0 rg (dispatch_on ) Tj /F1 10 Tf 0 0 0 rg (which can be used to) Tj T* 0 Tw .616905 Tw (implement generic functions dispatching on any argument; moreover it can manage dispatching on more) Tj T* 0 Tw (than one argument and, of course, it is signature-preserving.) Tj T* ET Q Q q 1 0 0 1 62.69291 134.0236 cm q BT 1 0 0 1 0 26 Tm 2.022765 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here I will give a very concrete example \(taken from a real-life use case\) where it is desiderable to) Tj T* 0 Tw .089984 Tw (dispatch on the second argument. Suppose you have an XMLWriter class, which is instantiated with some) Tj T* 0 Tw (configuration parameters and has a ) Tj /F3 10 Tf 0 0 0 rg (.write ) Tj /F1 10 Tf 0 0 0 rg (method which is able to serialize objects to XML:) Tj T* ET Q Q q 1 0 0 1 62.69291 88.82362 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 30 12 re f* .960784 .960784 .862745 rg n 36 12 54 12 re f* .960784 .960784 .862745 rg n 90 12 6 12 re f* .960784 .960784 .862745 rg n 96 12 36 12 re f* .960784 .960784 .862745 rg n 132 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 18 12 re f* .960784 .960784 .862745 rg n 48 0 48 12 re f* .960784 .960784 .862745 rg n 96 0 6 12 re f* .960784 .960784 .862745 rg n 102 0 24 12 re f* .960784 .960784 .862745 rg n 126 0 6 12 re f* .960784 .960784 .862745 rg n 138 0 12 12 re f* .960784 .960784 .862745 rg n 150 0 36 12 re f* .960784 .960784 .862745 rg n 186 0 12 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (class) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 0 1 rg (XMLWriter) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (__init__) Tj 0 0 0 rg (\() Tj 0 .501961 0 rg (self) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (config) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ET Q Q Q Q Q endstream endobj 117 0 obj << /Length 15681 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 691.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 72 re B* Q q .960784 .960784 .862745 rg n 48 48 24 12 re f* .960784 .960784 .862745 rg n 72 48 6 12 re f* .960784 .960784 .862745 rg n 78 48 18 12 re f* .960784 .960784 .862745 rg n 102 48 6 12 re f* .960784 .960784 .862745 rg n 114 48 36 12 re f* .960784 .960784 .862745 rg n 24 24 72 12 re f* .960784 .960784 .862745 rg n 96 24 6 12 re f* .960784 .960784 .862745 rg n 102 24 30 12 re f* .960784 .960784 .862745 rg n 132 24 6 12 re f* .960784 .960784 .862745 rg n 24 12 18 12 re f* .960784 .960784 .862745 rg n 48 12 30 12 re f* .960784 .960784 .862745 rg n 78 12 6 12 re f* .960784 .960784 .862745 rg n 84 12 24 12 re f* .960784 .960784 .862745 rg n 108 12 6 12 re f* .960784 .960784 .862745 rg n 120 12 18 12 re f* .960784 .960784 .862745 rg n 138 12 12 12 re f* .960784 .960784 .862745 rg n 48 0 30 12 re f* .960784 .960784 .862745 rg n 84 0 114 12 re f* .960784 .960784 .862745 rg n 198 0 6 12 re f* .960784 .960784 .862745 rg n 204 0 24 12 re f* .960784 .960784 .862745 rg n 228 0 6 12 re f* .960784 .960784 .862745 rg n 234 0 18 12 re f* .960784 .960784 .862745 rg n 252 0 12 12 re f* BT 1 0 0 1 0 50 Tm 12 TL /F3 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (cfg) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (config) Tj 0 0 0 rg T* T* ( ) Tj .666667 .133333 1 rg (@dispatch_on) Tj 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ('obj') Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (write) Tj 0 0 0 rg (\() Tj 0 .501961 0 rg (self) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (obj) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (raise) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf .823529 .254902 .227451 rg (NotImplementedError) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 .501961 0 rg (type) Tj 0 0 0 rg (\() Tj 0 0 0 rg (obj) Tj 0 0 0 rg (\)\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 611.8236 cm q BT 1 0 0 1 0 62 Tm 3.34936 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here you want to dispatch on the second argument since the first, ) Tj /F3 10 Tf 0 0 0 rg (self ) Tj /F1 10 Tf 0 0 0 rg (is already taken. The) Tj T* 0 Tw .544269 Tw /F3 10 Tf 0 0 0 rg (dispatch_on ) Tj /F1 10 Tf 0 0 0 rg (decorator factory allows you to specify the dispatch argument by simply passing its name) Tj T* 0 Tw .261988 Tw (as a string \(notice that if you mispell the name you will get an error\). The function decorated is turned into) Tj T* 0 Tw 1.747045 Tw (a generic function and it is the one which is called if there are no more specialized implementations.) Tj T* 0 Tw 1.959147 Tw (Usually such default function should raise a ) Tj /F3 10 Tf 0 0 0 rg (NotImplementedError) Tj /F1 10 Tf 0 0 0 rg (, thus forcing people to register) Tj T* 0 Tw (some implementation. The registration can be done with a decorator:) Tj T* ET Q Q q 1 0 0 1 62.69291 554.6236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q .960784 .960784 .862745 rg n 0 24 150 12 re f* .960784 .960784 .862745 rg n 150 24 6 12 re f* .960784 .960784 .862745 rg n 156 24 30 12 re f* .960784 .960784 .862745 rg n 186 24 6 12 re f* .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 24 12 60 12 re f* .960784 .960784 .862745 rg n 84 12 6 12 re f* .960784 .960784 .862745 rg n 90 12 24 12 re f* .960784 .960784 .862745 rg n 114 12 6 12 re f* .960784 .960784 .862745 rg n 126 12 18 12 re f* .960784 .960784 .862745 rg n 144 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 6 12 re f* .960784 .960784 .862745 rg n 72 0 6 12 re f* .960784 .960784 .862745 rg n 78 0 30 12 re f* .960784 .960784 .862745 rg n 108 0 6 12 re f* .960784 .960784 .862745 rg n 114 0 12 12 re f* .960784 .960784 .862745 rg n 126 0 6 12 re f* .960784 .960784 .862745 rg n 132 0 36 12 re f* .960784 .960784 .862745 rg n 168 0 6 12 re f* .960784 .960784 .862745 rg n 174 0 6 12 re f* .960784 .960784 .862745 rg n 186 0 6 12 re f* .960784 .960784 .862745 rg n 198 0 18 12 re f* BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf .666667 .133333 1 rg (@XMLWriter.write.register) Tj 0 0 0 rg (\() Tj 0 .501961 0 rg (float) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (writefloat) Tj 0 0 0 rg (\() Tj 0 .501961 0 rg (self) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (obj) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg (') Tj (<) Tj (float) Tj (>) Tj /F5 10 Tf .733333 .4 .533333 rg (%s) Tj /F3 10 Tf .729412 .129412 .129412 rg (<) Tj (/float) Tj (>) Tj (') Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (%) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (obj) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 534.6236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Now the XMLWriter is able to serialize floats:) Tj T* ET Q Q q 1 0 0 1 62.69291 477.4236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q .960784 .960784 .862745 rg n 0 24 6 12 re f* .960784 .960784 .862745 rg n 6 24 6 12 re f* .960784 .960784 .862745 rg n 12 24 6 12 re f* .960784 .960784 .862745 rg n 24 24 36 12 re f* .960784 .960784 .862745 rg n 66 24 6 12 re f* .960784 .960784 .862745 rg n 78 24 54 12 re f* .960784 .960784 .862745 rg n 132 24 12 12 re f* .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 36 12 re f* .960784 .960784 .862745 rg n 60 12 6 12 re f* .960784 .960784 .862745 rg n 66 12 30 12 re f* .960784 .960784 .862745 rg n 96 12 6 12 re f* .960784 .960784 .862745 rg n 102 12 18 12 re f* .960784 .960784 .862745 rg n 120 12 6 12 re f* .960784 .960784 .862745 rg n 0 0 6 12 re f* .960784 .960784 .862745 rg n 6 0 6 12 re f* .960784 .960784 .862745 rg n 12 0 30 12 re f* .960784 .960784 .862745 rg n 42 0 6 12 re f* .960784 .960784 .862745 rg n 48 0 18 12 re f* .960784 .960784 .862745 rg n 66 0 6 12 re f* .960784 .960784 .862745 rg n 72 0 36 12 re f* .960784 .960784 .862745 rg n 108 0 6 12 re f* .960784 .960784 .862745 rg n 114 0 6 12 re f* BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (writer) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (XMLWriter) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (writer) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (write) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (2.3) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .729412 .129412 .129412 rg (') Tj (<) Tj (float) Tj (>) Tj (2.3) Tj (<) Tj (/float) Tj (>) Tj (') Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 421.4236 cm q 0 0 0 rg BT 1 0 0 1 0 38 Tm /F1 10 Tf 12 TL .352209 Tw (I could give a down-to-earth example of situations in which it is desiderable to dispatch on more than one) Tj T* 0 Tw 3.67998 Tw (argument \(for instance once I implemented a database-access library where the first dispatching) Tj T* 0 Tw .442765 Tw (argument was the the database driver and the second one was the database record\), but here I prefer to) Tj T* 0 Tw (follow the tradition and show the time-honored Rock-Paper-Scissors example:) Tj T* ET Q Q q 1 0 0 1 62.69291 376.2236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 30 12 re f* .960784 .960784 .862745 rg n 36 12 24 12 re f* .960784 .960784 .862745 rg n 60 12 6 12 re f* .960784 .960784 .862745 rg n 66 12 36 12 re f* .960784 .960784 .862745 rg n 102 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 42 12 re f* .960784 .960784 .862745 rg n 72 0 6 12 re f* .960784 .960784 .862745 rg n 84 0 6 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (class) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 0 1 rg (Rock) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (ordinal) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (0) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 331.0236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 30 12 re f* .960784 .960784 .862745 rg n 36 12 30 12 re f* .960784 .960784 .862745 rg n 66 12 6 12 re f* .960784 .960784 .862745 rg n 72 12 36 12 re f* .960784 .960784 .862745 rg n 108 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 42 12 re f* .960784 .960784 .862745 rg n 72 0 6 12 re f* .960784 .960784 .862745 rg n 84 0 6 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (class) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 0 1 rg (Paper) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (ordinal) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (1) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 285.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 30 12 re f* .960784 .960784 .862745 rg n 36 12 48 12 re f* .960784 .960784 .862745 rg n 84 12 6 12 re f* .960784 .960784 .862745 rg n 90 12 36 12 re f* .960784 .960784 .862745 rg n 126 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 42 12 re f* .960784 .960784 .862745 rg n 72 0 6 12 re f* .960784 .960784 .862745 rg n 84 0 6 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (class) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 0 1 rg (Scissors) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (ordinal) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (2) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 193.8236 cm q BT 1 0 0 1 0 74 Tm .293735 Tw 12 TL /F1 10 Tf 0 0 0 rg (I have added an ordinal to the Rock-Paper-Scissors classes to simplify the implementation. The idea is to) Tj T* 0 Tw 1.821235 Tw (define a generic function ) Tj /F3 10 Tf 0 0 0 rg (win\(a, b\) ) Tj /F1 10 Tf 0 0 0 rg (of two arguments corresponding to the moves of the first and) Tj T* 0 Tw 1.487126 Tw (second player respectively. The moves are instances of the classes Rock, Paper and Scissors; Paper) Tj T* 0 Tw .587765 Tw (wins over Rock, Scissors wins over Paper and Rock wins over Scissors. The function will return +1 for a) Tj T* 0 Tw .353876 Tw (win, -1 for a loss and 0 for parity. There are 9 combinations, however combinations with the same ordinal) Tj T* 0 Tw .815542 Tw (\(i.e. the same class\) return 0; moreover by exchanging the order of the arguments the sign of the result) Tj T* 0 Tw (changes, so it is enough to specify directly only 3 implementations:) Tj T* ET Q Q q 1 0 0 1 62.69291 88.62362 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 96 re B* Q q .960784 .960784 .862745 rg n 0 72 72 12 re f* .960784 .960784 .862745 rg n 72 72 6 12 re f* .960784 .960784 .862745 rg n 78 72 18 12 re f* .960784 .960784 .862745 rg n 96 72 6 12 re f* .960784 .960784 .862745 rg n 108 72 18 12 re f* .960784 .960784 .862745 rg n 126 72 6 12 re f* .960784 .960784 .862745 rg n 0 60 18 12 re f* .960784 .960784 .862745 rg n 24 60 18 12 re f* .960784 .960784 .862745 rg n 42 60 6 12 re f* .960784 .960784 .862745 rg n 48 60 6 12 re f* .960784 .960784 .862745 rg n 54 60 6 12 re f* .960784 .960784 .862745 rg n 66 60 6 12 re f* .960784 .960784 .862745 rg n 72 60 12 12 re f* .960784 .960784 .862745 rg n 24 48 12 12 re f* .960784 .960784 .862745 rg n 42 48 6 12 re f* .960784 .960784 .862745 rg n 48 48 6 12 re f* .960784 .960784 .862745 rg n 54 48 42 12 re f* .960784 .960784 .862745 rg n 102 48 12 12 re f* .960784 .960784 .862745 rg n 120 48 6 12 re f* .960784 .960784 .862745 rg n 126 48 6 12 re f* .960784 .960784 .862745 rg n 132 48 42 12 re f* .960784 .960784 .862745 rg n 174 48 6 12 re f* .960784 .960784 .862745 rg n 48 36 36 12 re f* .960784 .960784 .862745 rg n 90 36 6 12 re f* .960784 .960784 .862745 rg n 24 24 24 12 re f* .960784 .960784 .862745 rg n 54 24 6 12 re f* .960784 .960784 .862745 rg n 60 24 6 12 re f* .960784 .960784 .862745 rg n 66 24 42 12 re f* .960784 .960784 .862745 rg n 114 24 6 12 re f* .960784 .960784 .862745 rg n 126 24 6 12 re f* .960784 .960784 .862745 rg n 132 24 6 12 re f* .960784 .960784 .862745 rg n 138 24 42 12 re f* .960784 .960784 .862745 rg n 180 24 6 12 re f* .960784 .960784 .862745 rg n 48 12 36 12 re f* .960784 .960784 .862745 rg n 90 12 6 12 re f* .960784 .960784 .862745 rg n 96 12 18 12 re f* .960784 .960784 .862745 rg n 114 12 6 12 re f* .960784 .960784 .862745 rg n 120 12 6 12 re f* .960784 .960784 .862745 rg n 126 12 6 12 re f* .960784 .960784 .862745 rg n 138 12 6 12 re f* .960784 .960784 .862745 rg n 144 12 6 12 re f* .960784 .960784 .862745 rg n 24 0 30 12 re f* .960784 .960784 .862745 rg n 60 0 114 12 re f* .960784 .960784 .862745 rg n 174 0 12 12 re f* .960784 .960784 .862745 rg n 186 0 24 12 re f* .960784 .960784 .862745 rg n 210 0 6 12 re f* .960784 .960784 .862745 rg n 216 0 6 12 re f* .960784 .960784 .862745 rg n 222 0 12 12 re f* .960784 .960784 .862745 rg n 240 0 24 12 re f* .960784 .960784 .862745 rg n 264 0 6 12 re f* .960784 .960784 .862745 rg n 270 0 6 12 re f* .960784 .960784 .862745 rg n 276 0 18 12 re f* BT 1 0 0 1 0 74 Tm 12 TL /F3 10 Tf .666667 .133333 1 rg (@dispatch_on) Tj 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ('a') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('b') Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (win) Tj 0 0 0 rg (\() Tj 0 0 0 rg (a) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (b) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (if) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (a) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (ordinal) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (==) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (b) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (ordinal) Tj 0 0 0 rg (:) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .4 .4 .4 rg (0) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (elif) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (a) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (ordinal) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (b) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (ordinal) Tj 0 0 0 rg (:) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .4 .4 .4 rg (-) Tj 0 0 0 rg (win) Tj 0 0 0 rg (\() Tj 0 0 0 rg (b) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (a) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (raise) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf .823529 .254902 .227451 rg (NotImplementedError) Tj /F3 10 Tf 0 0 0 rg (\(\() Tj 0 .501961 0 rg (type) Tj 0 0 0 rg (\() Tj 0 0 0 rg (a) Tj 0 0 0 rg (\),) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (type) Tj 0 0 0 rg (\() Tj 0 0 0 rg (b) Tj 0 0 0 rg (\)\)\)) Tj T* ET Q Q Q Q Q endstream endobj 118 0 obj << /Length 15246 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 715.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q .960784 .960784 .862745 rg n 0 24 78 12 re f* .960784 .960784 .862745 rg n 78 24 6 12 re f* .960784 .960784 .862745 rg n 84 24 24 12 re f* .960784 .960784 .862745 rg n 108 24 6 12 re f* .960784 .960784 .862745 rg n 120 24 30 12 re f* .960784 .960784 .862745 rg n 150 24 6 12 re f* .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 24 12 72 12 re f* .960784 .960784 .862745 rg n 96 12 6 12 re f* .960784 .960784 .862745 rg n 102 12 6 12 re f* .960784 .960784 .862745 rg n 108 12 6 12 re f* .960784 .960784 .862745 rg n 120 12 6 12 re f* .960784 .960784 .862745 rg n 126 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 6 12 re f* .960784 .960784 .862745 rg n 72 0 6 12 re f* BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf .666667 .133333 1 rg (@win.register) Tj 0 0 0 rg (\() Tj 0 0 0 rg (Rock) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (Paper) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (winRockPaper) Tj 0 0 0 rg (\() Tj 0 0 0 rg (a) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (b) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .4 .4 .4 rg (-) Tj .4 .4 .4 rg (1) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 658.6236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q .960784 .960784 .862745 rg n 0 24 78 12 re f* .960784 .960784 .862745 rg n 78 24 6 12 re f* .960784 .960784 .862745 rg n 84 24 30 12 re f* .960784 .960784 .862745 rg n 114 24 6 12 re f* .960784 .960784 .862745 rg n 126 24 48 12 re f* .960784 .960784 .862745 rg n 174 24 6 12 re f* .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 24 12 96 12 re f* .960784 .960784 .862745 rg n 120 12 6 12 re f* .960784 .960784 .862745 rg n 126 12 6 12 re f* .960784 .960784 .862745 rg n 132 12 6 12 re f* .960784 .960784 .862745 rg n 144 12 6 12 re f* .960784 .960784 .862745 rg n 150 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 6 12 re f* .960784 .960784 .862745 rg n 72 0 6 12 re f* BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf .666667 .133333 1 rg (@win.register) Tj 0 0 0 rg (\() Tj 0 0 0 rg (Paper) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (Scissors) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (winPaperScissors) Tj 0 0 0 rg (\() Tj 0 0 0 rg (a) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (b) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .4 .4 .4 rg (-) Tj .4 .4 .4 rg (1) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 601.4236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q .960784 .960784 .862745 rg n 0 24 78 12 re f* .960784 .960784 .862745 rg n 78 24 6 12 re f* .960784 .960784 .862745 rg n 84 24 24 12 re f* .960784 .960784 .862745 rg n 108 24 6 12 re f* .960784 .960784 .862745 rg n 120 24 48 12 re f* .960784 .960784 .862745 rg n 168 24 6 12 re f* .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 24 12 90 12 re f* .960784 .960784 .862745 rg n 114 12 6 12 re f* .960784 .960784 .862745 rg n 120 12 6 12 re f* .960784 .960784 .862745 rg n 126 12 6 12 re f* .960784 .960784 .862745 rg n 138 12 6 12 re f* .960784 .960784 .862745 rg n 144 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 6 12 re f* BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf .666667 .133333 1 rg (@win.register) Tj 0 0 0 rg (\() Tj 0 0 0 rg (Rock) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (Scissors) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (winRockScissors) Tj 0 0 0 rg (\() Tj 0 0 0 rg (a) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (b) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .4 .4 .4 rg (1) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 581.4236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Here is the result:) Tj T* ET Q Q q 1 0 0 1 62.69291 344.2236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 228 re B* Q q .960784 .960784 .862745 rg n 0 204 6 12 re f* .960784 .960784 .862745 rg n 6 204 6 12 re f* .960784 .960784 .862745 rg n 12 204 6 12 re f* .960784 .960784 .862745 rg n 24 204 18 12 re f* .960784 .960784 .862745 rg n 42 204 6 12 re f* .960784 .960784 .862745 rg n 48 204 30 12 re f* .960784 .960784 .862745 rg n 78 204 18 12 re f* .960784 .960784 .862745 rg n 102 204 24 12 re f* .960784 .960784 .862745 rg n 126 204 18 12 re f* .960784 .960784 .862745 rg n 0 192 6 12 re f* .960784 .960784 .862745 rg n 0 180 6 12 re f* .960784 .960784 .862745 rg n 6 180 6 12 re f* .960784 .960784 .862745 rg n 12 180 6 12 re f* .960784 .960784 .862745 rg n 24 180 18 12 re f* .960784 .960784 .862745 rg n 42 180 6 12 re f* .960784 .960784 .862745 rg n 48 180 48 12 re f* .960784 .960784 .862745 rg n 96 180 18 12 re f* .960784 .960784 .862745 rg n 120 180 30 12 re f* .960784 .960784 .862745 rg n 150 180 18 12 re f* .960784 .960784 .862745 rg n 0 168 6 12 re f* .960784 .960784 .862745 rg n 0 156 6 12 re f* .960784 .960784 .862745 rg n 6 156 6 12 re f* .960784 .960784 .862745 rg n 12 156 6 12 re f* .960784 .960784 .862745 rg n 24 156 18 12 re f* .960784 .960784 .862745 rg n 42 156 6 12 re f* .960784 .960784 .862745 rg n 48 156 24 12 re f* .960784 .960784 .862745 rg n 72 156 18 12 re f* .960784 .960784 .862745 rg n 96 156 48 12 re f* .960784 .960784 .862745 rg n 144 156 18 12 re f* .960784 .960784 .862745 rg n 0 144 6 12 re f* .960784 .960784 .862745 rg n 0 132 6 12 re f* .960784 .960784 .862745 rg n 6 132 6 12 re f* .960784 .960784 .862745 rg n 12 132 6 12 re f* .960784 .960784 .862745 rg n 24 132 18 12 re f* .960784 .960784 .862745 rg n 42 132 6 12 re f* .960784 .960784 .862745 rg n 48 132 30 12 re f* .960784 .960784 .862745 rg n 78 132 18 12 re f* .960784 .960784 .862745 rg n 102 132 30 12 re f* .960784 .960784 .862745 rg n 132 132 18 12 re f* .960784 .960784 .862745 rg n 0 120 6 12 re f* .960784 .960784 .862745 rg n 0 108 6 12 re f* .960784 .960784 .862745 rg n 6 108 6 12 re f* .960784 .960784 .862745 rg n 12 108 6 12 re f* .960784 .960784 .862745 rg n 24 108 18 12 re f* .960784 .960784 .862745 rg n 42 108 6 12 re f* .960784 .960784 .862745 rg n 48 108 24 12 re f* .960784 .960784 .862745 rg n 72 108 18 12 re f* .960784 .960784 .862745 rg n 96 108 24 12 re f* .960784 .960784 .862745 rg n 120 108 18 12 re f* .960784 .960784 .862745 rg n 0 96 6 12 re f* .960784 .960784 .862745 rg n 0 84 6 12 re f* .960784 .960784 .862745 rg n 6 84 6 12 re f* .960784 .960784 .862745 rg n 12 84 6 12 re f* .960784 .960784 .862745 rg n 24 84 18 12 re f* .960784 .960784 .862745 rg n 42 84 6 12 re f* .960784 .960784 .862745 rg n 48 84 48 12 re f* .960784 .960784 .862745 rg n 96 84 18 12 re f* .960784 .960784 .862745 rg n 120 84 48 12 re f* .960784 .960784 .862745 rg n 168 84 18 12 re f* .960784 .960784 .862745 rg n 0 72 6 12 re f* .960784 .960784 .862745 rg n 0 60 6 12 re f* .960784 .960784 .862745 rg n 6 60 6 12 re f* .960784 .960784 .862745 rg n 12 60 6 12 re f* .960784 .960784 .862745 rg n 24 60 18 12 re f* .960784 .960784 .862745 rg n 42 60 6 12 re f* .960784 .960784 .862745 rg n 48 60 24 12 re f* .960784 .960784 .862745 rg n 72 60 18 12 re f* .960784 .960784 .862745 rg n 96 60 30 12 re f* .960784 .960784 .862745 rg n 126 60 18 12 re f* .960784 .960784 .862745 rg n 0 48 6 12 re f* .960784 .960784 .862745 rg n 6 48 6 12 re f* .960784 .960784 .862745 rg n 0 36 6 12 re f* .960784 .960784 .862745 rg n 6 36 6 12 re f* .960784 .960784 .862745 rg n 12 36 6 12 re f* .960784 .960784 .862745 rg n 24 36 18 12 re f* .960784 .960784 .862745 rg n 42 36 6 12 re f* .960784 .960784 .862745 rg n 48 36 30 12 re f* .960784 .960784 .862745 rg n 78 36 18 12 re f* .960784 .960784 .862745 rg n 102 36 48 12 re f* .960784 .960784 .862745 rg n 150 36 18 12 re f* .960784 .960784 .862745 rg n 0 24 6 12 re f* .960784 .960784 .862745 rg n 6 24 6 12 re f* .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 18 12 re f* .960784 .960784 .862745 rg n 42 12 6 12 re f* .960784 .960784 .862745 rg n 48 12 48 12 re f* .960784 .960784 .862745 rg n 96 12 18 12 re f* .960784 .960784 .862745 rg n 120 12 24 12 re f* .960784 .960784 .862745 rg n 144 12 18 12 re f* .960784 .960784 .862745 rg n 0 0 6 12 re f* .960784 .960784 .862745 rg n 6 0 6 12 re f* BT 1 0 0 1 0 206 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (win) Tj 0 0 0 rg (\() Tj 0 0 0 rg (Paper) Tj 0 0 0 rg (\(\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (Rock) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg T* .4 .4 .4 rg (1) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (win) Tj 0 0 0 rg (\() Tj 0 0 0 rg (Scissors) Tj 0 0 0 rg (\(\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (Paper) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg T* .4 .4 .4 rg (1) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (win) Tj 0 0 0 rg (\() Tj 0 0 0 rg (Rock) Tj 0 0 0 rg (\(\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (Scissors) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg T* .4 .4 .4 rg (1) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (win) Tj 0 0 0 rg (\() Tj 0 0 0 rg (Paper) Tj 0 0 0 rg (\(\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (Paper) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg T* .4 .4 .4 rg (0) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (win) Tj 0 0 0 rg (\() Tj 0 0 0 rg (Rock) Tj 0 0 0 rg (\(\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (Rock) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg T* .4 .4 .4 rg (0) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (win) Tj 0 0 0 rg (\() Tj 0 0 0 rg (Scissors) Tj 0 0 0 rg (\(\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (Scissors) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg T* .4 .4 .4 rg (0) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (win) Tj 0 0 0 rg (\() Tj 0 0 0 rg (Rock) Tj 0 0 0 rg (\(\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (Paper) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg T* .4 .4 .4 rg (-) Tj .4 .4 .4 rg (1) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (win) Tj 0 0 0 rg (\() Tj 0 0 0 rg (Paper) Tj 0 0 0 rg (\(\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (Scissors) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg T* .4 .4 .4 rg (-) Tj .4 .4 .4 rg (1) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (win) Tj 0 0 0 rg (\() Tj 0 0 0 rg (Scissors) Tj 0 0 0 rg (\(\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (Rock) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg T* .4 .4 .4 rg (-) Tj .4 .4 .4 rg (1) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 312.2236 cm q 0 0 0 rg BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .76528 Tw (The point of generic functions is that they play well with subclassing. For instance, suppose we define a) Tj T* 0 Tw (StrongRock which does not lose against Paper:) Tj T* ET Q Q q 1 0 0 1 62.69291 267.0236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 30 12 re f* .960784 .960784 .862745 rg n 36 12 60 12 re f* .960784 .960784 .862745 rg n 96 12 6 12 re f* .960784 .960784 .862745 rg n 102 12 24 12 re f* .960784 .960784 .862745 rg n 126 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 24 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (class) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 0 1 rg (StrongRock) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (Rock) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (pass) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 209.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q .960784 .960784 .862745 rg n 0 24 78 12 re f* .960784 .960784 .862745 rg n 78 24 6 12 re f* .960784 .960784 .862745 rg n 84 24 60 12 re f* .960784 .960784 .862745 rg n 144 24 6 12 re f* .960784 .960784 .862745 rg n 156 24 30 12 re f* .960784 .960784 .862745 rg n 186 24 6 12 re f* .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 24 12 108 12 re f* .960784 .960784 .862745 rg n 132 12 6 12 re f* .960784 .960784 .862745 rg n 138 12 6 12 re f* .960784 .960784 .862745 rg n 144 12 6 12 re f* .960784 .960784 .862745 rg n 156 12 6 12 re f* .960784 .960784 .862745 rg n 162 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 6 12 re f* BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf .666667 .133333 1 rg (@win.register) Tj 0 0 0 rg (\() Tj 0 0 0 rg (StrongRock) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (Paper) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (winStrongRockPaper) Tj 0 0 0 rg (\() Tj 0 0 0 rg (a) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (b) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .4 .4 .4 rg (0) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 189.8236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Then we do not need to define other implementations, since they are inherited from the parent:) Tj T* ET Q Q q 1 0 0 1 62.69291 144.6236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 18 12 re f* .960784 .960784 .862745 rg n 42 12 6 12 re f* .960784 .960784 .862745 rg n 48 12 60 12 re f* .960784 .960784 .862745 rg n 108 12 18 12 re f* .960784 .960784 .862745 rg n 132 12 48 12 re f* .960784 .960784 .862745 rg n 180 12 18 12 re f* .960784 .960784 .862745 rg n 0 0 6 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (win) Tj 0 0 0 rg (\() Tj 0 0 0 rg (StrongRock) Tj 0 0 0 rg (\(\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (Scissors) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg T* .4 .4 .4 rg (1) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 112.6236 cm q BT 1 0 0 1 0 14 Tm 12.49998 Tw 12 TL /F1 10 Tf 0 0 0 rg (You can introspect the precedence used by the dispath algorithm by calling) Tj T* 0 Tw /F3 10 Tf 0 0 0 rg (.dispatch_info\(*types\)) Tj /F1 10 Tf 0 0 0 rg (:) Tj T* ET Q Q endstream endobj 119 0 obj << /Length 11458 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 727.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 18 12 re f* .960784 .960784 .862745 rg n 42 12 6 12 re f* .960784 .960784 .862745 rg n 48 12 78 12 re f* .960784 .960784 .862745 rg n 126 12 6 12 re f* .960784 .960784 .862745 rg n 132 12 60 12 re f* .960784 .960784 .862745 rg n 192 12 6 12 re f* .960784 .960784 .862745 rg n 204 12 48 12 re f* .960784 .960784 .862745 rg n 252 12 6 12 re f* .960784 .960784 .862745 rg n 0 0 12 12 re f* .960784 .960784 .862745 rg n 12 0 72 12 re f* .960784 .960784 .862745 rg n 84 0 6 12 re f* .960784 .960784 .862745 rg n 96 0 60 12 re f* .960784 .960784 .862745 rg n 156 0 12 12 re f* .960784 .960784 .862745 rg n 174 0 6 12 re f* .960784 .960784 .862745 rg n 180 0 36 12 re f* .960784 .960784 .862745 rg n 216 0 6 12 re f* .960784 .960784 .862745 rg n 228 0 60 12 re f* .960784 .960784 .862745 rg n 288 0 12 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (win) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (dispatch_info) Tj 0 0 0 rg (\() Tj 0 0 0 rg (StrongRock) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (Scissors) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* 0 0 0 rg ([\() Tj .729412 .129412 .129412 rg ('StrongRock') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('Scissors') Tj 0 0 0 rg (\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ('Rock') Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('Scissors') Tj 0 0 0 rg (\)]) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 671.8236 cm q BT 1 0 0 1 0 38 Tm 3.354269 Tw 12 TL /F1 10 Tf 0 0 0 rg (Since there is no direct implementation for \(StrongRock, Scissors\) the dispatcher will look at the) Tj T* 0 Tw .352651 Tw (implementation for \(Rock, Scissors\) which is available. Internally the algorithm is doing a cross product of) Tj T* 0 Tw 1.64784 Tw (the class precedence lists \(or Method Resolution Orders, ) Tj 0 0 .501961 rg (MRO ) Tj 0 0 0 rg (for short\) of StrongRock and Scissors) Tj T* 0 Tw (respectively.) Tj T* ET Q Q q 1 0 0 1 62.69291 638.8236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Generic functions and virtual ancestors) Tj T* ET Q Q q 1 0 0 1 62.69291 608.8236 cm q 0 0 0 rg BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL 1.225366 Tw (Generic function implementations in Python are complicated by the existence of "virtual ancestors", i.e.) Tj T* 0 Tw (superclasses which are not in the class hierarchy. Consider for instance this class:) Tj T* ET Q Q q 1 0 0 1 62.69291 551.6236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q .960784 .960784 .862745 rg n 0 24 30 12 re f* .960784 .960784 .862745 rg n 36 24 60 12 re f* .960784 .960784 .862745 rg n 96 24 6 12 re f* .960784 .960784 .862745 rg n 102 24 36 12 re f* .960784 .960784 .862745 rg n 138 24 12 12 re f* .960784 .960784 .862745 rg n 24 12 18 12 re f* .960784 .960784 .862745 rg n 48 12 42 12 re f* .960784 .960784 .862745 rg n 90 12 6 12 re f* .960784 .960784 .862745 rg n 96 12 24 12 re f* .960784 .960784 .862745 rg n 120 12 12 12 re f* .960784 .960784 .862745 rg n 48 0 36 12 re f* .960784 .960784 .862745 rg n 90 0 6 12 re f* BT 1 0 0 1 0 26 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (class) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 0 1 rg (WithLength) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (__len__) Tj 0 0 0 rg (\() Tj 0 .501961 0 rg (self) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .4 .4 .4 rg (0) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 519.6236 cm q BT 1 0 0 1 0 14 Tm .772765 Tw 12 TL /F1 10 Tf 0 0 0 rg (This class defines a ) Tj /F3 10 Tf 0 0 0 rg (__len__ ) Tj /F1 10 Tf 0 0 0 rg (method and as such is considered to be a subclass of the abstract base) Tj T* 0 Tw (class ) Tj /F3 10 Tf 0 0 0 rg (collections.Sized) Tj /F1 10 Tf 0 0 0 rg (:) Tj T* ET Q Q q 1 0 0 1 62.69291 474.4236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 60 12 re f* .960784 .960784 .862745 rg n 84 12 6 12 re f* .960784 .960784 .862745 rg n 90 12 60 12 re f* .960784 .960784 .862745 rg n 150 12 6 12 re f* .960784 .960784 .862745 rg n 162 12 66 12 re f* .960784 .960784 .862745 rg n 228 12 6 12 re f* .960784 .960784 .862745 rg n 234 12 30 12 re f* .960784 .960784 .862745 rg n 264 12 6 12 re f* .960784 .960784 .862745 rg n 0 0 24 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (issubclass) Tj 0 0 0 rg (\() Tj 0 0 0 rg (WithLength) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (collections) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Sized) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* 0 .501961 0 rg (True) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 430.4236 cm q BT 1 0 0 1 0 26 Tm 2.414651 Tw 12 TL /F1 10 Tf 0 0 0 rg (However, ) Tj /F3 10 Tf 0 0 0 rg (collections.Sized ) Tj /F1 10 Tf 0 0 0 rg (is not in the ) Tj 0 0 .501961 rg (MRO ) Tj 0 0 0 rg (of ) Tj /F3 10 Tf 0 0 0 rg (WithLength) Tj /F1 10 Tf 0 0 0 rg (, it is not a true ancestor. Any) Tj T* 0 Tw .651412 Tw (implementation of generic functions, even with single dispatch, must go through some contorsion to take) Tj T* 0 Tw (into account the virtual ancestors.) Tj T* ET Q Q q 1 0 0 1 62.69291 412.4236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (In particular if we define a generic function) Tj T* ET Q Q q 1 0 0 1 62.69291 355.2236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q .960784 .960784 .862745 rg n 0 24 72 12 re f* .960784 .960784 .862745 rg n 72 24 6 12 re f* .960784 .960784 .862745 rg n 78 24 30 12 re f* .960784 .960784 .862745 rg n 108 24 6 12 re f* .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 24 12 60 12 re f* .960784 .960784 .862745 rg n 84 12 6 12 re f* .960784 .960784 .862745 rg n 90 12 18 12 re f* .960784 .960784 .862745 rg n 108 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 30 12 re f* .960784 .960784 .862745 rg n 60 0 114 12 re f* .960784 .960784 .862745 rg n 174 0 6 12 re f* .960784 .960784 .862745 rg n 180 0 24 12 re f* .960784 .960784 .862745 rg n 204 0 6 12 re f* .960784 .960784 .862745 rg n 210 0 18 12 re f* .960784 .960784 .862745 rg n 228 0 12 12 re f* BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf .666667 .133333 1 rg (@dispatch_on) Tj 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ('obj') Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (get_length) Tj 0 0 0 rg (\() Tj 0 0 0 rg (obj) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (raise) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf .823529 .254902 .227451 rg (NotImplementedError) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 .501961 0 rg (type) Tj 0 0 0 rg (\() Tj 0 0 0 rg (obj) Tj 0 0 0 rg (\)\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 335.2236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (implemented on all classes with a length) Tj T* ET Q Q q 1 0 0 1 62.69291 278.0236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q .960784 .960784 .862745 rg n 0 24 120 12 re f* .960784 .960784 .862745 rg n 120 24 6 12 re f* .960784 .960784 .862745 rg n 126 24 66 12 re f* .960784 .960784 .862745 rg n 192 24 6 12 re f* .960784 .960784 .862745 rg n 198 24 30 12 re f* .960784 .960784 .862745 rg n 228 24 6 12 re f* .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 24 12 96 12 re f* .960784 .960784 .862745 rg n 120 12 6 12 re f* .960784 .960784 .862745 rg n 126 12 18 12 re f* .960784 .960784 .862745 rg n 144 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 18 12 re f* .960784 .960784 .862745 rg n 84 0 6 12 re f* .960784 .960784 .862745 rg n 90 0 18 12 re f* .960784 .960784 .862745 rg n 108 0 6 12 re f* BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf .666667 .133333 1 rg (@get_length.register) Tj 0 0 0 rg (\() Tj 0 0 0 rg (collections) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Sized) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (get_length_sized) Tj 0 0 0 rg (\() Tj 0 0 0 rg (obj) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (len) Tj 0 0 0 rg (\() Tj 0 0 0 rg (obj) Tj 0 0 0 rg (\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 258.0236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (then ) Tj /F3 10 Tf 0 0 0 rg (get_length ) Tj /F1 10 Tf 0 0 0 rg (must be defined on ) Tj /F3 10 Tf 0 0 0 rg (WithLength ) Tj /F1 10 Tf 0 0 0 rg (instances) Tj T* ET Q Q q 1 0 0 1 62.69291 212.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 60 12 re f* .960784 .960784 .862745 rg n 84 12 6 12 re f* .960784 .960784 .862745 rg n 90 12 60 12 re f* .960784 .960784 .862745 rg n 150 12 18 12 re f* .960784 .960784 .862745 rg n 0 0 6 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (get_length) Tj 0 0 0 rg (\() Tj 0 0 0 rg (WithLength) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg T* .4 .4 .4 rg (0) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 180.8236 cm q BT 1 0 0 1 0 14 Tm 2.228651 Tw 12 TL /F1 10 Tf 0 0 0 rg (even if ) Tj /F3 10 Tf 0 0 0 rg (collections.Sized ) Tj /F1 10 Tf 0 0 0 rg (is not a true ancestor of ) Tj /F3 10 Tf 0 0 0 rg (WithLength) Tj /F1 10 Tf 0 0 0 rg (. Of course this is a contrived) Tj T* 0 Tw (example since you could just use the builtin ) Tj /F3 10 Tf 0 0 0 rg (len) Tj /F1 10 Tf 0 0 0 rg (, but you should get the idea.) Tj T* ET Q Q q 1 0 0 1 62.69291 138.8236 cm q BT 1 0 0 1 0 26 Tm .129461 Tw 12 TL /F1 10 Tf 0 0 0 rg (Since in Python it is possible to consider any instance of ABCMeta as a virtual ancestor of any other class) Tj T* 0 Tw .21152 Tw (\(it is enough to register it as ) Tj /F3 10 Tf 0 0 0 rg (ancestor.register\(cls\)) Tj /F1 10 Tf 0 0 0 rg (\), any implementation of generic functions must) Tj T* 0 Tw (take virtual ancestors into account. Let me give an example.) Tj T* ET Q Q q 1 0 0 1 62.69291 120.8236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Suppose you are using a third party set-like class like the following:) Tj T* ET Q Q endstream endobj 120 0 obj << /Length 13371 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 691.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 72 re B* Q q .960784 .960784 .862745 rg n 0 48 30 12 re f* .960784 .960784 .862745 rg n 36 48 42 12 re f* .960784 .960784 .862745 rg n 78 48 6 12 re f* .960784 .960784 .862745 rg n 84 48 66 12 re f* .960784 .960784 .862745 rg n 150 48 6 12 re f* .960784 .960784 .862745 rg n 156 48 30 12 re f* .960784 .960784 .862745 rg n 186 48 12 12 re f* .960784 .960784 .862745 rg n 24 36 216 12 re f* .960784 .960784 .862745 rg n 24 24 90 12 re f* .960784 .960784 .862745 rg n 24 12 18 12 re f* .960784 .960784 .862745 rg n 48 12 42 12 re f* .960784 .960784 .862745 rg n 90 12 6 12 re f* .960784 .960784 .862745 rg n 96 12 24 12 re f* .960784 .960784 .862745 rg n 120 12 12 12 re f* .960784 .960784 .862745 rg n 48 0 36 12 re f* .960784 .960784 .862745 rg n 90 0 6 12 re f* BT 1 0 0 1 0 50 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (class) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 0 1 rg (SomeSet) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (collections) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Sized) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# methods that make SomeSet set-like) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# not shown ...) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (__len__) Tj 0 0 0 rg (\() Tj 0 .501961 0 rg (self) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .4 .4 .4 rg (0) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 659.8236 cm q BT 1 0 0 1 0 14 Tm 1.042651 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here the author of ) Tj /F3 10 Tf 0 0 0 rg (SomeSet ) Tj /F1 10 Tf 0 0 0 rg (made a mistake by not inheriting from ) Tj /F3 10 Tf 0 0 0 rg (collections.Set) Tj /F1 10 Tf 0 0 0 rg (, but only from) Tj T* 0 Tw /F3 10 Tf 0 0 0 rg (collections.Sized) Tj /F1 10 Tf 0 0 0 rg (.) Tj T* ET Q Q q 1 0 0 1 62.69291 629.8236 cm q BT 1 0 0 1 0 14 Tm 1.588735 Tw 12 TL /F1 10 Tf 0 0 0 rg (This is not a problem since you can register ) Tj /F4 10 Tf (a posteriori) Tj /F1 10 Tf ( ) Tj /F3 10 Tf 0 0 0 rg (collections.Set ) Tj /F1 10 Tf 0 0 0 rg (as a virtual ancestor of) Tj T* 0 Tw /F3 10 Tf 0 0 0 rg (SomeSet) Tj /F1 10 Tf 0 0 0 rg (:) Tj T* ET Q Q q 1 0 0 1 62.69291 572.6236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q .960784 .960784 .862745 rg n 0 24 6 12 re f* .960784 .960784 .862745 rg n 6 24 6 12 re f* .960784 .960784 .862745 rg n 12 24 6 12 re f* .960784 .960784 .862745 rg n 24 24 6 12 re f* .960784 .960784 .862745 rg n 36 24 6 12 re f* .960784 .960784 .862745 rg n 48 24 66 12 re f* .960784 .960784 .862745 rg n 114 24 6 12 re f* .960784 .960784 .862745 rg n 120 24 18 12 re f* .960784 .960784 .862745 rg n 138 24 6 12 re f* .960784 .960784 .862745 rg n 144 24 48 12 re f* .960784 .960784 .862745 rg n 192 24 6 12 re f* .960784 .960784 .862745 rg n 198 24 42 12 re f* .960784 .960784 .862745 rg n 240 24 6 12 re f* .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 60 12 re f* .960784 .960784 .862745 rg n 84 12 6 12 re f* .960784 .960784 .862745 rg n 90 12 42 12 re f* .960784 .960784 .862745 rg n 132 12 6 12 re f* .960784 .960784 .862745 rg n 144 12 66 12 re f* .960784 .960784 .862745 rg n 210 12 6 12 re f* .960784 .960784 .862745 rg n 216 12 18 12 re f* .960784 .960784 .862745 rg n 234 12 6 12 re f* .960784 .960784 .862745 rg n 0 0 24 12 re f* BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (_) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (collections) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Set) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (register) Tj 0 0 0 rg (\() Tj 0 0 0 rg (SomeSet) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (issubclass) Tj 0 0 0 rg (\() Tj 0 0 0 rg (SomeSet) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (collections) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Set) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* 0 .501961 0 rg (True) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 552.6236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (Now, let us define an implementation of ) Tj /F3 10 Tf 0 0 0 rg (get_length ) Tj /F1 10 Tf 0 0 0 rg (specific to set:) Tj T* ET Q Q q 1 0 0 1 62.69291 495.4236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q .960784 .960784 .862745 rg n 0 24 120 12 re f* .960784 .960784 .862745 rg n 120 24 6 12 re f* .960784 .960784 .862745 rg n 126 24 66 12 re f* .960784 .960784 .862745 rg n 192 24 6 12 re f* .960784 .960784 .862745 rg n 198 24 18 12 re f* .960784 .960784 .862745 rg n 216 24 6 12 re f* .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 24 12 84 12 re f* .960784 .960784 .862745 rg n 108 12 6 12 re f* .960784 .960784 .862745 rg n 114 12 18 12 re f* .960784 .960784 .862745 rg n 132 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 6 12 re f* BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf .666667 .133333 1 rg (@get_length.register) Tj 0 0 0 rg (\() Tj 0 0 0 rg (collections) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Set) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (get_length_set) Tj 0 0 0 rg (\() Tj 0 0 0 rg (obj) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .4 .4 .4 rg (1) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 463.4236 cm q BT 1 0 0 1 0 14 Tm .210697 Tw 12 TL /F1 10 Tf 0 0 0 rg (The current implementation, as the one used by ) Tj /F3 10 Tf 0 0 0 rg (functools.singledispatch) Tj /F1 10 Tf 0 0 0 rg (, is able to discern that a) Tj T* 0 Tw /F3 10 Tf 0 0 0 rg (Set ) Tj /F1 10 Tf 0 0 0 rg (is a ) Tj /F3 10 Tf 0 0 0 rg (Sized ) Tj /F1 10 Tf 0 0 0 rg (object, so the more specific implementation for ) Tj /F3 10 Tf 0 0 0 rg (Set ) Tj /F1 10 Tf 0 0 0 rg (is taken:) Tj T* ET Q Q q 1 0 0 1 62.69291 418.2236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 36 re B* Q q .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 60 12 re f* .960784 .960784 .862745 rg n 84 12 6 12 re f* .960784 .960784 .862745 rg n 90 12 42 12 re f* .960784 .960784 .862745 rg n 132 12 18 12 re f* .960784 .960784 .862745 rg n 162 12 282 12 re f* .960784 .960784 .862745 rg n 0 0 6 12 re f* BT 1 0 0 1 0 14 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (get_length) Tj 0 0 0 rg (\() Tj 0 0 0 rg (SomeSet) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# NB: the implementation for Sized would give 0) Tj /F3 10 Tf 0 0 0 rg T* .4 .4 .4 rg (1) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 350.2236 cm q BT 1 0 0 1 0 50 Tm 3.503735 Tw 12 TL /F1 10 Tf 0 0 0 rg (Sometimes it is not clear how to dispatch. For instance, consider a class ) Tj /F3 10 Tf 0 0 0 rg (C ) Tj /F1 10 Tf 0 0 0 rg (registered both as) Tj T* 0 Tw 6.519974 Tw /F3 10 Tf 0 0 0 rg (collections.Iterable ) Tj /F1 10 Tf 0 0 0 rg (and ) Tj /F3 10 Tf 0 0 0 rg (collections.Sized ) Tj /F1 10 Tf 0 0 0 rg (and define a generic function ) Tj /F3 10 Tf 0 0 0 rg (g ) Tj /F1 10 Tf 0 0 0 rg (with) Tj T* 0 Tw 3.101085 Tw (implementations both for ) Tj /F3 10 Tf 0 0 0 rg (collections.Iterable ) Tj /F1 10 Tf 0 0 0 rg (and ) Tj /F3 10 Tf 0 0 0 rg (collections.Sized) Tj /F1 10 Tf 0 0 0 rg (. It is impossible to) Tj T* 0 Tw .690697 Tw (decide which implementation to use, since the ancestors are independent, and the following function will) Tj T* 0 Tw (raise a RuntimeError when called:) Tj T* ET Q Q q 1 0 0 1 62.69291 137.0236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 204 re B* Q q .960784 .960784 .862745 rg n 0 180 18 12 re f* .960784 .960784 .862745 rg n 24 180 138 12 re f* .960784 .960784 .862745 rg n 162 180 18 12 re f* .960784 .960784 .862745 rg n 24 168 84 12 re f* .960784 .960784 .862745 rg n 114 168 6 12 re f* .960784 .960784 .862745 rg n 126 168 66 12 re f* .960784 .960784 .862745 rg n 192 168 6 12 re f* .960784 .960784 .862745 rg n 198 168 30 12 re f* .960784 .960784 .862745 rg n 228 168 6 12 re f* .960784 .960784 .862745 rg n 24 144 90 12 re f* .960784 .960784 .862745 rg n 24 132 18 12 re f* .960784 .960784 .862745 rg n 48 132 6 12 re f* .960784 .960784 .862745 rg n 54 132 6 12 re f* .960784 .960784 .862745 rg n 60 132 18 12 re f* .960784 .960784 .862745 rg n 78 132 12 12 re f* .960784 .960784 .862745 rg n 48 120 30 12 re f* .960784 .960784 .862745 rg n 84 120 114 12 re f* .960784 .960784 .862745 rg n 198 120 6 12 re f* .960784 .960784 .862745 rg n 204 120 24 12 re f* .960784 .960784 .862745 rg n 228 120 6 12 re f* .960784 .960784 .862745 rg n 234 120 6 12 re f* .960784 .960784 .862745 rg n 240 120 12 12 re f* .960784 .960784 .862745 rg n 24 96 66 12 re f* .960784 .960784 .862745 rg n 90 96 6 12 re f* .960784 .960784 .862745 rg n 96 96 66 12 re f* .960784 .960784 .862745 rg n 162 96 6 12 re f* .960784 .960784 .862745 rg n 168 96 30 12 re f* .960784 .960784 .862745 rg n 198 96 6 12 re f* .960784 .960784 .862745 rg n 24 84 18 12 re f* .960784 .960784 .862745 rg n 48 84 42 12 re f* .960784 .960784 .862745 rg n 90 84 6 12 re f* .960784 .960784 .862745 rg n 96 84 36 12 re f* .960784 .960784 .862745 rg n 132 84 12 12 re f* .960784 .960784 .862745 rg n 48 72 36 12 re f* .960784 .960784 .862745 rg n 90 72 42 12 re f* .960784 .960784 .862745 rg n 24 48 66 12 re f* .960784 .960784 .862745 rg n 90 48 6 12 re f* .960784 .960784 .862745 rg n 96 48 66 12 re f* .960784 .960784 .862745 rg n 162 48 6 12 re f* .960784 .960784 .862745 rg n 168 48 48 12 re f* .960784 .960784 .862745 rg n 216 48 6 12 re f* .960784 .960784 .862745 rg n 24 36 18 12 re f* .960784 .960784 .862745 rg n 48 36 60 12 re f* .960784 .960784 .862745 rg n 108 36 6 12 re f* .960784 .960784 .862745 rg n 114 36 36 12 re f* .960784 .960784 .862745 rg n 150 36 12 12 re f* .960784 .960784 .862745 rg n 48 24 36 12 re f* .960784 .960784 .862745 rg n 90 24 60 12 re f* .960784 .960784 .862745 rg n 24 0 6 12 re f* .960784 .960784 .862745 rg n 30 0 6 12 re f* .960784 .960784 .862745 rg n 36 0 6 12 re f* .960784 .960784 .862745 rg n 42 0 18 12 re f* .960784 .960784 .862745 rg n 72 0 324 12 re f* BT 1 0 0 1 0 182 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (singledispatch_example1) Tj 0 0 0 rg (\(\):) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (singledispatch) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (dispatch_on) Tj 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ('obj') Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* T* ( ) Tj .666667 .133333 1 rg (@singledispatch) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (g) Tj 0 0 0 rg (\() Tj 0 0 0 rg (obj) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (raise) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf .823529 .254902 .227451 rg (NotImplementedError) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 .501961 0 rg (type) Tj 0 0 0 rg (\() Tj 0 0 0 rg (g) Tj 0 0 0 rg (\)\)) Tj 0 0 0 rg T* T* ( ) Tj .666667 .133333 1 rg (@g.register) Tj 0 0 0 rg (\() Tj 0 0 0 rg (collections) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Sized) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (g_sized) Tj 0 0 0 rg (\() Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("sized") Tj 0 0 0 rg T* T* ( ) Tj .666667 .133333 1 rg (@g.register) Tj 0 0 0 rg (\() Tj 0 0 0 rg (collections) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Iterable) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (g_iterable) Tj 0 0 0 rg (\() Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("iterable") Tj 0 0 0 rg T* T* ( ) Tj 0 0 0 rg (g) Tj 0 0 0 rg (\() Tj 0 0 0 rg (C) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# RuntimeError: Ambiguous dispatch: Iterable or Sized?) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 105.0236 cm q BT 1 0 0 1 0 14 Tm .745433 Tw 12 TL /F1 10 Tf 0 0 0 rg (This is consistent with the "refuse the temptation to guess" philosophy. ) Tj /F3 10 Tf 0 0 0 rg (functools.singledispatch) Tj T* 0 Tw /F1 10 Tf 0 0 0 rg (would raise a similar error.) Tj T* ET Q Q endstream endobj 121 0 obj << /Length 14304 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 693.0236 cm q 0 0 0 rg BT 1 0 0 1 0 62 Tm /F1 10 Tf 12 TL .01104 Tw (It would be easy to rely on the order of registration to decide the precedence order. This is reasonable, but) Tj T* 0 Tw 3.788555 Tw (also fragile: if during some refactoring you change the registration order by mistake, a different) Tj T* 0 Tw 3.585814 Tw (implementation could be taken. If implementations of the generic functions are distributed across) Tj T* 0 Tw .939984 Tw (modules, and you change the import order, a different implementation could be taken. So the decorator) Tj T* 0 Tw .128935 Tw (module prefers to raise an error in the face of ambiguity. This is the same approach taken by the standard) Tj T* 0 Tw (library.) Tj T* ET Q Q q 1 0 0 1 62.69291 627.0236 cm q BT 1 0 0 1 0 50 Tm .743735 Tw 12 TL /F1 10 Tf 0 0 0 rg (However, it should be noticed that the dispatch algorithm used by the decorator module is different from) Tj T* 0 Tw 2.269398 Tw (the one used by the standard library, so there are cases where you will get different answers. The) Tj T* 0 Tw 1.830814 Tw (difference is that ) Tj /F3 10 Tf 0 0 0 rg (functools.singledispatch ) Tj /F1 10 Tf 0 0 0 rg (tries to insert the virtual ancestors ) Tj /F4 10 Tf (before ) Tj /F1 10 Tf (the base) Tj T* 0 Tw 1.149983 Tw (classes, whereas ) Tj /F3 10 Tf 0 0 0 rg (decorator.dispatch_on ) Tj /F1 10 Tf 0 0 0 rg (tries to insert them ) Tj /F4 10 Tf (after ) Tj /F1 10 Tf (the base classes. I will give an) Tj T* 0 Tw (example showing the difference:) Tj T* ET Q Q q 1 0 0 1 62.69291 269.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 348 re B* Q q .960784 .960784 .862745 rg n 0 324 18 12 re f* .960784 .960784 .862745 rg n 24 324 138 12 re f* .960784 .960784 .862745 rg n 162 324 18 12 re f* .960784 .960784 .862745 rg n 24 312 294 12 re f* .960784 .960784 .862745 rg n 24 300 84 12 re f* .960784 .960784 .862745 rg n 114 300 6 12 re f* .960784 .960784 .862745 rg n 126 300 66 12 re f* .960784 .960784 .862745 rg n 192 300 6 12 re f* .960784 .960784 .862745 rg n 198 300 30 12 re f* .960784 .960784 .862745 rg n 228 300 6 12 re f* .960784 .960784 .862745 rg n 24 276 30 12 re f* .960784 .960784 .862745 rg n 60 276 6 12 re f* .960784 .960784 .862745 rg n 66 276 6 12 re f* .960784 .960784 .862745 rg n 72 276 36 12 re f* .960784 .960784 .862745 rg n 108 276 12 12 re f* .960784 .960784 .862745 rg n 48 264 24 12 re f* .960784 .960784 .862745 rg n 24 240 30 12 re f* .960784 .960784 .862745 rg n 60 240 6 12 re f* .960784 .960784 .862745 rg n 66 240 6 12 re f* .960784 .960784 .862745 rg n 72 240 6 12 re f* .960784 .960784 .862745 rg n 78 240 6 12 re f* .960784 .960784 .862745 rg n 84 240 30 12 re f* .960784 .960784 .862745 rg n 114 240 6 12 re f* .960784 .960784 .862745 rg n 126 240 6 12 re f* .960784 .960784 .862745 rg n 132 240 12 12 re f* .960784 .960784 .862745 rg n 48 228 18 12 re f* .960784 .960784 .862745 rg n 72 228 42 12 re f* .960784 .960784 .862745 rg n 114 228 6 12 re f* .960784 .960784 .862745 rg n 120 228 24 12 re f* .960784 .960784 .862745 rg n 144 228 12 12 re f* .960784 .960784 .862745 rg n 72 216 36 12 re f* .960784 .960784 .862745 rg n 114 216 6 12 re f* .960784 .960784 .862745 rg n 24 192 90 12 re f* .960784 .960784 .862745 rg n 24 180 18 12 re f* .960784 .960784 .862745 rg n 48 180 6 12 re f* .960784 .960784 .862745 rg n 54 180 6 12 re f* .960784 .960784 .862745 rg n 60 180 18 12 re f* .960784 .960784 .862745 rg n 78 180 12 12 re f* .960784 .960784 .862745 rg n 48 168 36 12 re f* .960784 .960784 .862745 rg n 90 168 36 12 re f* .960784 .960784 .862745 rg n 24 144 66 12 re f* .960784 .960784 .862745 rg n 90 144 6 12 re f* .960784 .960784 .862745 rg n 96 144 6 12 re f* .960784 .960784 .862745 rg n 102 144 6 12 re f* .960784 .960784 .862745 rg n 24 132 18 12 re f* .960784 .960784 .862745 rg n 48 132 18 12 re f* .960784 .960784 .862745 rg n 66 132 6 12 re f* .960784 .960784 .862745 rg n 72 132 18 12 re f* .960784 .960784 .862745 rg n 90 132 12 12 re f* .960784 .960784 .862745 rg n 48 120 36 12 re f* .960784 .960784 .862745 rg n 90 120 18 12 re f* .960784 .960784 .862745 rg n 24 96 66 12 re f* .960784 .960784 .862745 rg n 90 96 6 12 re f* .960784 .960784 .862745 rg n 96 96 6 12 re f* .960784 .960784 .862745 rg n 102 96 6 12 re f* .960784 .960784 .862745 rg n 108 96 54 12 re f* .960784 .960784 .862745 rg n 162 96 6 12 re f* .960784 .960784 .862745 rg n 24 84 18 12 re f* .960784 .960784 .862745 rg n 48 84 66 12 re f* .960784 .960784 .862745 rg n 114 84 6 12 re f* .960784 .960784 .862745 rg n 120 84 18 12 re f* .960784 .960784 .862745 rg n 138 84 12 12 re f* .960784 .960784 .862745 rg n 48 72 36 12 re f* .960784 .960784 .862745 rg n 90 72 66 12 re f* .960784 .960784 .862745 rg n 24 48 6 12 re f* .960784 .960784 .862745 rg n 36 48 6 12 re f* .960784 .960784 .862745 rg n 48 48 6 12 re f* .960784 .960784 .862745 rg n 54 48 12 12 re f* .960784 .960784 .862745 rg n 24 36 36 12 re f* .960784 .960784 .862745 rg n 66 36 6 12 re f* .960784 .960784 .862745 rg n 72 36 6 12 re f* .960784 .960784 .862745 rg n 78 36 6 12 re f* .960784 .960784 .862745 rg n 84 36 6 12 re f* .960784 .960784 .862745 rg n 96 36 12 12 re f* .960784 .960784 .862745 rg n 114 36 18 12 re f* .960784 .960784 .862745 rg n 24 24 6 12 re f* .960784 .960784 .862745 rg n 30 24 6 12 re f* .960784 .960784 .862745 rg n 36 24 54 12 re f* .960784 .960784 .862745 rg n 90 24 6 12 re f* .960784 .960784 .862745 rg n 96 24 48 12 re f* .960784 .960784 .862745 rg n 144 24 6 12 re f* .960784 .960784 .862745 rg n 150 24 6 12 re f* .960784 .960784 .862745 rg n 156 24 6 12 re f* .960784 .960784 .862745 rg n 174 24 246 12 re f* .960784 .960784 .862745 rg n 24 12 36 12 re f* .960784 .960784 .862745 rg n 66 12 6 12 re f* .960784 .960784 .862745 rg n 72 12 6 12 re f* .960784 .960784 .862745 rg n 78 12 6 12 re f* .960784 .960784 .862745 rg n 84 12 6 12 re f* .960784 .960784 .862745 rg n 96 12 12 12 re f* .960784 .960784 .862745 rg n 114 12 18 12 re f* .960784 .960784 .862745 rg n 144 12 294 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 6 12 re f* .960784 .960784 .862745 rg n 72 0 6 12 re f* .960784 .960784 .862745 rg n 84 0 6 12 re f* BT 1 0 0 1 0 326 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (singledispatch_example2) Tj 0 0 0 rg (\(\):) Tj 0 0 0 rg T* ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# adapted from functools.singledispatch test case) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj 0 0 0 rg (singledispatch) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (dispatch_on) Tj 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ('arg') Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (class) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 0 1 rg (S) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (pass) Tj /F3 10 Tf 0 0 0 rg T* T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (class) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf 0 0 1 rg (V) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (c) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Sized) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (S) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (__len__) Tj 0 0 0 rg (\() Tj 0 .501961 0 rg (self) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .4 .4 .4 rg (0) Tj 0 0 0 rg T* T* ( ) Tj .666667 .133333 1 rg (@singledispatch) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (g) Tj 0 0 0 rg (\() Tj 0 0 0 rg (arg) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("base") Tj 0 0 0 rg T* T* ( ) Tj .666667 .133333 1 rg (@g.register) Tj 0 0 0 rg (\() Tj 0 0 0 rg (S) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (g_s) Tj 0 0 0 rg (\() Tj 0 0 0 rg (arg) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("s") Tj 0 0 0 rg T* T* ( ) Tj .666667 .133333 1 rg (@g.register) Tj 0 0 0 rg (\() Tj 0 0 0 rg (c) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Container) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (g_container) Tj 0 0 0 rg (\() Tj 0 0 0 rg (arg) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("container") Tj 0 0 0 rg T* T* ( ) Tj 0 0 0 rg (v) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (V) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (assert) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (g) Tj 0 0 0 rg (\() Tj 0 0 0 rg (v) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (==) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("s") Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (c) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Container) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (register) Tj 0 0 0 rg (\() Tj 0 0 0 rg (V) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# add c.Container to the virtual mro of V) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (assert) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (g) Tj 0 0 0 rg (\() Tj 0 0 0 rg (v) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (==) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("s") Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# since the virtual mro is V, Sized, S, Container) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (g) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (V) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 201.8236 cm q BT 1 0 0 1 0 50 Tm 10.88816 Tw 12 TL /F1 10 Tf 0 0 0 rg (If you play with this example and replace the ) Tj /F3 10 Tf 0 0 0 rg (singledispatch ) Tj /F1 10 Tf 0 0 0 rg (definition with) Tj T* 0 Tw 2.720888 Tw /F3 10 Tf 0 0 0 rg (functools.singledispatch) Tj /F1 10 Tf 0 0 0 rg (, the assert will break: ) Tj /F3 10 Tf 0 0 0 rg (g ) Tj /F1 10 Tf 0 0 0 rg (will return ) Tj /F3 10 Tf 0 0 0 rg ("container" ) Tj /F1 10 Tf 0 0 0 rg (instead of ) Tj /F3 10 Tf 0 0 0 rg ("s") Tj /F1 10 Tf 0 0 0 rg (,) Tj T* 0 Tw .779147 Tw (because ) Tj /F3 10 Tf 0 0 0 rg (functools.singledispatch ) Tj /F1 10 Tf 0 0 0 rg (will insert the ) Tj /F3 10 Tf 0 0 0 rg (Container ) Tj /F1 10 Tf 0 0 0 rg (class right before ) Tj /F3 10 Tf 0 0 0 rg (S) Tj /F1 10 Tf 0 0 0 rg (. The only way) Tj T* 0 Tw .259431 Tw (to understand what is happening here is to scratch your head by looking at the implementations. I will just) Tj T* 0 Tw (notice that ) Tj /F3 10 Tf 0 0 0 rg (.dispatch_info ) Tj /F1 10 Tf 0 0 0 rg (is quite useful:) Tj T* ET Q Q q 1 0 0 1 62.69291 144.6236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q .960784 .960784 .862745 rg n 0 24 6 12 re f* .960784 .960784 .862745 rg n 6 24 6 12 re f* .960784 .960784 .862745 rg n 12 24 6 12 re f* .960784 .960784 .862745 rg n 24 24 6 12 re f* .960784 .960784 .862745 rg n 30 24 6 12 re f* .960784 .960784 .862745 rg n 42 24 6 12 re f* .960784 .960784 .862745 rg n 54 24 6 12 re f* .960784 .960784 .862745 rg n 66 24 138 12 re f* .960784 .960784 .862745 rg n 204 24 12 12 re f* .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 6 12 re f* .960784 .960784 .862745 rg n 30 12 6 12 re f* .960784 .960784 .862745 rg n 36 12 78 12 re f* .960784 .960784 .862745 rg n 114 12 6 12 re f* .960784 .960784 .862745 rg n 120 12 6 12 re f* .960784 .960784 .862745 rg n 126 12 6 12 re f* .960784 .960784 .862745 rg n 0 0 12 12 re f* .960784 .960784 .862745 rg n 12 0 18 12 re f* .960784 .960784 .862745 rg n 30 0 18 12 re f* .960784 .960784 .862745 rg n 54 0 6 12 re f* .960784 .960784 .862745 rg n 60 0 42 12 re f* .960784 .960784 .862745 rg n 102 0 18 12 re f* .960784 .960784 .862745 rg n 126 0 6 12 re f* .960784 .960784 .862745 rg n 132 0 18 12 re f* .960784 .960784 .862745 rg n 150 0 18 12 re f* .960784 .960784 .862745 rg n 174 0 6 12 re f* .960784 .960784 .862745 rg n 180 0 66 12 re f* .960784 .960784 .862745 rg n 246 0 18 12 re f* BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (g) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (V) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (singledispatch_example2) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (g) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (dispatch_info) Tj 0 0 0 rg (\() Tj 0 0 0 rg (V) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* 0 0 0 rg ([\() Tj .729412 .129412 .129412 rg ('V') Tj 0 0 0 rg (,\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ('Sized') Tj 0 0 0 rg (,\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ('S') Tj 0 0 0 rg (,\),) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ('Container') Tj 0 0 0 rg (,\)]) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 112.6236 cm q BT 1 0 0 1 0 14 Tm 1.409147 Tw 12 TL /F1 10 Tf 0 0 0 rg (The current implementation does not implement any kind of cooperation between implementations, i.e.) Tj T* 0 Tw (there is nothing akin to call-next-method in Lisp, nor akin to ) Tj /F3 10 Tf 0 0 0 rg (super ) Tj /F1 10 Tf 0 0 0 rg (in Python.) Tj T* ET Q Q q 1 0 0 1 62.69291 82.62362 cm q BT 1 0 0 1 0 14 Tm .22186 Tw 12 TL /F1 10 Tf 0 0 0 rg (Finally, let me notice that the decorator module implementation does not use any cache, whereas the one) Tj T* 0 Tw (in ) Tj /F3 10 Tf 0 0 0 rg (singledispatch ) Tj /F1 10 Tf 0 0 0 rg (has a cache.) Tj T* ET Q Q endstream endobj 122 0 obj << /Length 9635 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 744.0236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Caveats and limitations) Tj T* ET Q Q q 1 0 0 1 62.69291 714.0236 cm q 0 0 0 rg BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .259431 Tw (One thing you should be aware of, is the performance penalty of decorators. The worse case is shown by) Tj T* 0 Tw (the following example:) Tj T* ET Q Q q 1 0 0 1 62.69291 488.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 216 re B* Q q 0 0 0 rg BT 1 0 0 1 0 194 Tm /F3 10 Tf 12 TL ($ cat performance.sh) Tj T* (python3 -m timeit -s ") Tj T* (from decorator import decorator) Tj T* T* (@decorator) Tj T* (def do_nothing\(func, *args, **kw\):) Tj T* ( return func\(*args, **kw\)) Tj T* T* (@do_nothing) Tj T* (def f\(\):) Tj T* ( pass) Tj T* (" "f\(\)") Tj T* T* (python3 -m timeit -s ") Tj T* (def f\(\):) Tj T* ( pass) Tj T* (" "f\(\)") Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 468.8236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (On my laptop, using the ) Tj /F3 10 Tf 0 0 0 rg (do_nothing ) Tj /F1 10 Tf 0 0 0 rg (decorator instead of the plain function is five times slower:) Tj T* ET Q Q q 1 0 0 1 62.69291 411.6236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q 0 0 0 rg BT 1 0 0 1 0 26 Tm /F3 10 Tf 12 TL ($ bash performance.sh) Tj T* (1000000 loops, best of 3: 1.39 usec per loop) Tj T* (1000000 loops, best of 3: 0.278 usec per loop) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 367.6236 cm q BT 1 0 0 1 0 26 Tm 1.25832 Tw 12 TL /F1 10 Tf 0 0 0 rg (It should be noted that a real life function would probably do something more useful than ) Tj /F3 10 Tf 0 0 0 rg (f ) Tj /F1 10 Tf 0 0 0 rg (here, and) Tj T* 0 Tw .91811 Tw (therefore in real life the performance penalty could be completely negligible. As always, the only way to) Tj T* 0 Tw (know if there is a penalty in your specific use case is to measure it.) Tj T* ET Q Q q 1 0 0 1 62.69291 337.6236 cm q 0 0 0 rg BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .091984 Tw (More importantly, you should be aware that decorators will make your tracebacks longer and more difficult) Tj T* 0 Tw (to understand. Consider this example:) Tj T* ET Q Q q 1 0 0 1 62.69291 280.4236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q .960784 .960784 .862745 rg n 0 24 6 12 re f* .960784 .960784 .862745 rg n 6 24 6 12 re f* .960784 .960784 .862745 rg n 12 24 6 12 re f* .960784 .960784 .862745 rg n 24 24 36 12 re f* .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 24 12 18 12 re f* .960784 .960784 .862745 rg n 48 12 6 12 re f* .960784 .960784 .862745 rg n 54 12 18 12 re f* .960784 .960784 .862745 rg n 0 0 18 12 re f* .960784 .960784 .862745 rg n 48 0 6 12 re f* .960784 .960784 .862745 rg n 54 0 6 12 re f* .960784 .960784 .862745 rg n 60 0 6 12 re f* BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj .666667 .133333 1 rg (@trace) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (f) Tj 0 0 0 rg (\(\):) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (1) Tj .4 .4 .4 rg (/) Tj .4 .4 .4 rg (0) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 248.4236 cm q BT 1 0 0 1 0 14 Tm .583318 Tw 12 TL /F1 10 Tf 0 0 0 rg (Calling ) Tj /F3 10 Tf 0 0 0 rg (f\(\) ) Tj /F1 10 Tf 0 0 0 rg (will give you a ) Tj /F3 10 Tf 0 0 0 rg (ZeroDivisionError) Tj /F1 10 Tf 0 0 0 rg (, but since the function is decorated the traceback will) Tj T* 0 Tw (be longer:) Tj T* ET Q Q q 1 0 0 1 62.69291 119.2236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 120 re B* Q q .960784 .960784 .862745 rg n 0 96 6 12 re f* .960784 .960784 .862745 rg n 6 96 6 12 re f* .960784 .960784 .862745 rg n 12 96 6 12 re f* .960784 .960784 .862745 rg n 24 96 6 12 re f* .960784 .960784 .862745 rg n 30 96 12 12 re f* .960784 .960784 .862745 rg n 0 84 54 12 re f* .960784 .960784 .862745 rg n 60 84 6 12 re f* .960784 .960784 .862745 rg n 66 84 24 12 re f* .960784 .960784 .862745 rg n 96 84 36 12 re f* .960784 .960784 .862745 rg n 138 84 24 12 re f* .960784 .960784 .862745 rg n 168 84 24 12 re f* .960784 .960784 .862745 rg n 192 84 12 12 re f* .960784 .960784 .862745 rg n 12 72 18 12 re f* .960784 .960784 .862745 rg n 30 60 24 12 re f* .960784 .960784 .862745 rg n 60 60 6 12 re f* .960784 .960784 .862745 rg n 66 60 6 12 re f* .960784 .960784 .862745 rg n 72 60 36 12 re f* .960784 .960784 .862745 rg n 108 60 6 12 re f* .960784 .960784 .862745 rg n 114 60 6 12 re f* .960784 .960784 .862745 rg n 120 60 6 12 re f* .960784 .960784 .862745 rg n 132 60 24 12 re f* .960784 .960784 .862745 rg n 162 60 6 12 re f* .960784 .960784 .862745 rg n 168 60 6 12 re f* .960784 .960784 .862745 rg n 180 60 12 12 re f* .960784 .960784 .862745 rg n 198 60 6 12 re f* .960784 .960784 .862745 rg n 30 48 24 12 re f* .960784 .960784 .862745 rg n 60 48 6 12 re f* .960784 .960784 .862745 rg n 66 48 6 12 re f* .960784 .960784 .862745 rg n 72 48 120 12 re f* .960784 .960784 .862745 rg n 192 48 6 12 re f* .960784 .960784 .862745 rg n 198 48 6 12 re f* .960784 .960784 .862745 rg n 204 48 6 12 re f* .960784 .960784 .862745 rg n 216 48 24 12 re f* .960784 .960784 .862745 rg n 246 48 6 12 re f* .960784 .960784 .862745 rg n 252 48 6 12 re f* .960784 .960784 .862745 rg n 264 48 12 12 re f* .960784 .960784 .862745 rg n 282 48 30 12 re f* .960784 .960784 .862745 rg n 42 36 36 12 re f* .960784 .960784 .862745 rg n 84 36 6 12 re f* .960784 .960784 .862745 rg n 90 36 6 12 re f* .960784 .960784 .862745 rg n 96 36 6 12 re f* .960784 .960784 .862745 rg n 102 36 24 12 re f* .960784 .960784 .862745 rg n 126 36 6 12 re f* .960784 .960784 .862745 rg n 138 36 12 12 re f* .960784 .960784 .862745 rg n 150 36 12 12 re f* .960784 .960784 .862745 rg n 162 36 6 12 re f* .960784 .960784 .862745 rg n 30 24 24 12 re f* .960784 .960784 .862745 rg n 60 24 6 12 re f* .960784 .960784 .862745 rg n 66 24 6 12 re f* .960784 .960784 .862745 rg n 72 24 120 12 re f* .960784 .960784 .862745 rg n 192 24 6 12 re f* .960784 .960784 .862745 rg n 198 24 6 12 re f* .960784 .960784 .862745 rg n 204 24 6 12 re f* .960784 .960784 .862745 rg n 216 24 24 12 re f* .960784 .960784 .862745 rg n 246 24 6 12 re f* .960784 .960784 .862745 rg n 252 24 6 12 re f* .960784 .960784 .862745 rg n 264 24 12 12 re f* .960784 .960784 .862745 rg n 282 24 6 12 re f* .960784 .960784 .862745 rg n 42 12 6 12 re f* .960784 .960784 .862745 rg n 48 12 6 12 re f* .960784 .960784 .862745 rg n 54 12 6 12 re f* .960784 .960784 .862745 rg n 0 0 102 12 re f* .960784 .960784 .862745 rg n 102 0 6 12 re f* .960784 .960784 .862745 rg n 114 0 18 12 re f* BT 1 0 0 1 0 98 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg T* 0 0 0 rg (Traceback) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (\() Tj 0 0 0 rg (most) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (recent) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (call) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (last) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj .4 .4 .4 rg (...) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (File) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg (") Tj (<) Tj (string) Tj (>) Tj (") Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (line) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj /F5 10 Tf .666667 .133333 1 rg (in) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (f) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (File) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg (") Tj (<) Tj (doctest __main__[22]) Tj (>) Tj (") Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (line) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (4) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj /F5 10 Tf .666667 .133333 1 rg (in) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (trace) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (f) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (File) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg (") Tj (<) Tj (doctest __main__[51]) Tj (>) Tj (") Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (line) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (3) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj /F5 10 Tf .666667 .133333 1 rg (in) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (f) Tj 0 0 0 rg T* ( ) Tj .4 .4 .4 rg (1) Tj .4 .4 .4 rg (/) Tj .4 .4 .4 rg (0) Tj 0 0 0 rg T* /F5 10 Tf .823529 .254902 .227451 rg (ZeroDivisionError) Tj /F3 10 Tf 0 0 0 rg (:) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (...) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 87.22362 cm q BT 1 0 0 1 0 14 Tm 1.05528 Tw 12 TL /F1 10 Tf 0 0 0 rg (You see here the inner call to the decorator ) Tj /F3 10 Tf 0 0 0 rg (trace) Tj /F1 10 Tf 0 0 0 rg (, which calls ) Tj /F3 10 Tf 0 0 0 rg (f\(*args,) Tj ( ) Tj (**kw\)) Tj /F1 10 Tf 0 0 0 rg (, and a reference to ) Tj T* 0 Tw .076457 Tw /F3 10 Tf 0 0 0 rg (File) Tj ( ) Tj (") Tj (<) Tj (string) Tj (>) Tj (",) Tj ( ) Tj (line) Tj ( ) Tj (2,) Tj ( ) Tj (in) Tj ( ) Tj (f) Tj /F1 10 Tf 0 0 0 rg (. This latter reference is due to the fact that internally the decorator) Tj T* 0 Tw ET Q Q endstream endobj 123 0 obj << /Length 15420 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 729.0236 cm q BT 1 0 0 1 0 26 Tm 2.053318 Tw 12 TL /F1 10 Tf 0 0 0 rg (module uses ) Tj /F3 10 Tf 0 0 0 rg (exec ) Tj /F1 10 Tf 0 0 0 rg (to generate the decorated function. Notice that ) Tj /F3 10 Tf 0 0 0 rg (exec ) Tj /F1 10 Tf 0 0 0 rg (is ) Tj /F4 10 Tf (not ) Tj /F1 10 Tf (responsibile for the) Tj T* 0 Tw 1.507485 Tw (performance penalty, since is the called ) Tj /F4 10 Tf (only once ) Tj /F1 10 Tf (at function decoration time, and not every time the) Tj T* 0 Tw (decorated function is called.) Tj T* ET Q Q q 1 0 0 1 62.69291 615.0236 cm q BT 1 0 0 1 0 98 Tm .932209 Tw 12 TL /F1 10 Tf 0 0 0 rg (At present, there is no clean way to avoid ) Tj /F3 10 Tf 0 0 0 rg (exec) Tj /F1 10 Tf 0 0 0 rg (. A clean solution would require to change the CPython) Tj T* 0 Tw 2.348651 Tw (implementation of functions and add an hook to make it possible to change their signature directly.) Tj T* 0 Tw 2.793984 Tw (However, at present, even in Python 3.5 it is impossible to change the function signature directly,) Tj T* 0 Tw .329985 Tw (therefore the ) Tj /F3 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf 0 0 0 rg (module is still useful. Actually, this is the main reasons why I keep maintaining) Tj T* 0 Tw .042209 Tw (the module and releasing new versions. It should be noticed that in Python 3.5 a lot of improvements have) Tj T* 0 Tw 2.06998 Tw (been made: in that version you can decorated a function with ) Tj /F3 10 Tf 0 0 0 rg (func_tools.update_wrapper ) Tj /F1 10 Tf 0 0 0 rg (and) Tj T* 0 Tw 1.128735 Tw /F3 10 Tf 0 0 0 rg (pydoc ) Tj /F1 10 Tf 0 0 0 rg (will see the correct signature; still internally the function will have an incorrect signature, as you) Tj T* 0 Tw 1.10748 Tw (can see by using ) Tj /F3 10 Tf 0 0 0 rg (inspect.getfullargspec) Tj /F1 10 Tf 0 0 0 rg (: all documentation tools using such function \(which has) Tj T* 0 Tw (been correctly deprecated\) will see the wrong signature.) Tj T* ET Q Q q 1 0 0 1 62.69291 561.0236 cm q BT 1 0 0 1 0 38 Tm 1.043828 Tw 12 TL /F1 10 Tf 0 0 0 rg (In the present implementation, decorators generated by ) Tj /F3 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf 0 0 0 rg (can only be used on user-defined) Tj T* 0 Tw .152485 Tw (Python functions or methods, not on generic callable objects, nor on built-in functions, due to limitations of) Tj T* 0 Tw 2.15881 Tw (the ) Tj /F3 10 Tf 0 0 0 rg (inspect ) Tj /F1 10 Tf 0 0 0 rg (module in the standard library, especially for Python 2.X \(in Python 3.5 a lot of such) Tj T* 0 Tw (limitations have been removed\).) Tj T* ET Q Q q 1 0 0 1 62.69291 519.0236 cm q 0 0 0 rg BT 1 0 0 1 0 26 Tm /F1 10 Tf 12 TL 3.312651 Tw (There is a strange quirk when decorating functions that take keyword arguments, if one of such) Tj T* 0 Tw .765868 Tw (arguments has the same name used in the caller function for the first argument. The quirk was reported) Tj T* 0 Tw (by David Goldstein and here is an example where it is manifest:) Tj T* ET Q Q q 1 0 0 1 62.69291 413.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 96 re B* Q q .960784 .960784 .862745 rg n 0 72 6 12 re f* .960784 .960784 .862745 rg n 6 72 6 12 re f* .960784 .960784 .862745 rg n 12 72 6 12 re f* .960784 .960784 .862745 rg n 24 72 48 12 re f* .960784 .960784 .862745 rg n 0 60 18 12 re f* .960784 .960784 .862745 rg n 24 60 18 12 re f* .960784 .960784 .862745 rg n 48 60 42 12 re f* .960784 .960784 .862745 rg n 90 60 6 12 re f* .960784 .960784 .862745 rg n 96 60 12 12 re f* .960784 .960784 .862745 rg n 108 60 12 12 re f* .960784 .960784 .862745 rg n 120 60 12 12 re f* .960784 .960784 .862745 rg n 0 48 18 12 re f* .960784 .960784 .862745 rg n 48 48 36 12 re f* .960784 .960784 .862745 rg n 90 48 12 12 re f* .960784 .960784 .862745 rg n 102 48 6 12 re f* .960784 .960784 .862745 rg n 108 48 24 12 re f* .960784 .960784 .862745 rg n 132 48 12 12 re f* .960784 .960784 .862745 rg n 0 36 6 12 re f* .960784 .960784 .862745 rg n 6 36 6 12 re f* .960784 .960784 .862745 rg n 12 36 6 12 re f* .960784 .960784 .862745 rg n 24 36 42 12 re f* .960784 .960784 .862745 rg n 66 36 6 12 re f* .960784 .960784 .862745 rg n 72 36 24 12 re f* .960784 .960784 .862745 rg n 96 36 6 12 re f* .960784 .960784 .862745 rg n 102 36 18 12 re f* .960784 .960784 .862745 rg n 120 36 6 12 re f* .960784 .960784 .862745 rg n 0 24 54 12 re f* .960784 .960784 .862745 rg n 60 24 6 12 re f* .960784 .960784 .862745 rg n 66 24 24 12 re f* .960784 .960784 .862745 rg n 96 24 36 12 re f* .960784 .960784 .862745 rg n 138 24 24 12 re f* .960784 .960784 .862745 rg n 168 24 24 12 re f* .960784 .960784 .862745 rg n 192 24 12 12 re f* .960784 .960784 .862745 rg n 6 12 18 12 re f* .960784 .960784 .862745 rg n 0 0 54 12 re f* .960784 .960784 .862745 rg n 54 0 6 12 re f* .960784 .960784 .862745 rg n 66 0 48 12 re f* .960784 .960784 .862745 rg n 114 0 12 12 re f* .960784 .960784 .862745 rg n 132 0 18 12 re f* .960784 .960784 .862745 rg n 156 0 48 12 re f* .960784 .960784 .862745 rg n 210 0 36 12 re f* .960784 .960784 .862745 rg n 252 0 18 12 re f* .960784 .960784 .862745 rg n 276 0 18 12 re f* .960784 .960784 .862745 rg n 300 0 36 12 re f* BT 1 0 0 1 0 74 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj .666667 .133333 1 rg (@memoize) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (getkeys) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (kw) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (keys) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (getkeys) Tj 0 0 0 rg (\() Tj 0 0 0 rg (func) Tj .4 .4 .4 rg (=) Tj .729412 .129412 .129412 rg ('a') Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* 0 0 0 rg (Traceback) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (\() Tj 0 0 0 rg (most) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (recent) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (call) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (last) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj .4 .4 .4 rg (...) Tj 0 0 0 rg T* /F5 10 Tf .823529 .254902 .227451 rg (TypeError) Tj /F3 10 Tf 0 0 0 rg (:) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (_memoize) Tj 0 0 0 rg (\(\)) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (got) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (multiple) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (values) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (for) Tj /F3 10 Tf 0 0 0 rg ( ) Tj .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('func') Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 357.8236 cm q BT 1 0 0 1 0 38 Tm .988735 Tw 12 TL /F1 10 Tf 0 0 0 rg (The error message looks really strange until you realize that the caller function ) Tj /F4 10 Tf 0 0 0 rg (_memoize ) Tj /F1 10 Tf 0 0 0 rg (uses ) Tj /F4 10 Tf 0 0 0 rg (func ) Tj /F1 10 Tf 0 0 0 rg (as) Tj T* 0 Tw .496651 Tw (first argument, so there is a confusion between the positional argument and the keywork arguments. The) Tj T* 0 Tw 1.25528 Tw (solution is to change the name of the first argument in ) Tj /F4 10 Tf 0 0 0 rg (_memoize) Tj /F1 10 Tf 0 0 0 rg (, or to change the implementation as) Tj T* 0 Tw (follows:) Tj T* ET Q Q q 1 0 0 1 62.69291 204.6236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 144 re B* Q q .960784 .960784 .862745 rg n 0 120 18 12 re f* .960784 .960784 .862745 rg n 24 120 48 12 re f* .960784 .960784 .862745 rg n 72 120 6 12 re f* .960784 .960784 .862745 rg n 78 120 6 12 re f* .960784 .960784 .862745 rg n 84 120 48 12 re f* .960784 .960784 .862745 rg n 132 120 6 12 re f* .960784 .960784 .862745 rg n 144 120 12 12 re f* .960784 .960784 .862745 rg n 156 120 12 12 re f* .960784 .960784 .862745 rg n 168 120 12 12 re f* .960784 .960784 .862745 rg n 24 108 24 12 re f* .960784 .960784 .862745 rg n 54 108 6 12 re f* .960784 .960784 .862745 rg n 66 108 48 12 re f* .960784 .960784 .862745 rg n 114 108 6 12 re f* .960784 .960784 .862745 rg n 120 108 6 12 re f* .960784 .960784 .862745 rg n 126 108 6 12 re f* .960784 .960784 .862745 rg n 24 96 24 12 re f* .960784 .960784 .862745 rg n 54 96 6 12 re f* .960784 .960784 .862745 rg n 66 96 48 12 re f* .960784 .960784 .862745 rg n 114 96 6 12 re f* .960784 .960784 .862745 rg n 120 96 6 12 re f* .960784 .960784 .862745 rg n 126 96 12 12 re f* .960784 .960784 .862745 rg n 24 84 12 12 re f* .960784 .960784 .862745 rg n 42 84 12 12 re f* .960784 .960784 .862745 rg n 54 84 6 12 re f* .960784 .960784 .862745 rg n 72 84 246 12 re f* .960784 .960784 .862745 rg n 48 72 18 12 re f* .960784 .960784 .862745 rg n 72 72 6 12 re f* .960784 .960784 .862745 rg n 84 72 24 12 re f* .960784 .960784 .862745 rg n 108 72 6 12 re f* .960784 .960784 .862745 rg n 120 72 54 12 re f* .960784 .960784 .862745 rg n 174 72 6 12 re f* .960784 .960784 .862745 rg n 180 72 12 12 re f* .960784 .960784 .862745 rg n 192 72 6 12 re f* .960784 .960784 .862745 rg n 198 72 30 12 re f* .960784 .960784 .862745 rg n 228 72 18 12 re f* .960784 .960784 .862745 rg n 24 60 24 12 re f* .960784 .960784 .862745 rg n 48 60 6 12 re f* .960784 .960784 .862745 rg n 48 48 18 12 re f* .960784 .960784 .862745 rg n 72 48 6 12 re f* .960784 .960784 .862745 rg n 84 48 24 12 re f* .960784 .960784 .862745 rg n 24 36 30 12 re f* .960784 .960784 .862745 rg n 60 36 6 12 re f* .960784 .960784 .862745 rg n 72 36 24 12 re f* .960784 .960784 .862745 rg n 96 36 6 12 re f* .960784 .960784 .862745 rg n 102 36 30 12 re f* .960784 .960784 .862745 rg n 144 36 168 12 re f* .960784 .960784 .862745 rg n 24 24 12 12 re f* .960784 .960784 .862745 rg n 42 24 18 12 re f* .960784 .960784 .862745 rg n 66 24 18 12 re f* .960784 .960784 .862745 rg n 90 24 12 12 re f* .960784 .960784 .862745 rg n 108 24 30 12 re f* .960784 .960784 .862745 rg n 138 24 6 12 re f* .960784 .960784 .862745 rg n 48 12 30 12 re f* .960784 .960784 .862745 rg n 78 12 6 12 re f* .960784 .960784 .862745 rg n 84 12 18 12 re f* .960784 .960784 .862745 rg n 102 12 6 12 re f* .960784 .960784 .862745 rg n 114 12 6 12 re f* .960784 .960784 .862745 rg n 126 12 24 12 re f* .960784 .960784 .862745 rg n 150 12 6 12 re f* .960784 .960784 .862745 rg n 156 12 6 12 re f* .960784 .960784 .862745 rg n 162 12 24 12 re f* .960784 .960784 .862745 rg n 186 12 6 12 re f* .960784 .960784 .862745 rg n 198 12 12 12 re f* .960784 .960784 .862745 rg n 210 12 12 12 re f* .960784 .960784 .862745 rg n 222 12 6 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 30 12 re f* .960784 .960784 .862745 rg n 96 0 6 12 re f* .960784 .960784 .862745 rg n 102 0 18 12 re f* .960784 .960784 .862745 rg n 120 0 6 12 re f* BT 1 0 0 1 0 122 Tm 12 TL /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (_memoize) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (all_args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (func) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (all_args) Tj 0 0 0 rg ([) Tj .4 .4 .4 rg (0) Tj 0 0 0 rg (]) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (args) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (all_args) Tj 0 0 0 rg ([) Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (:]) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (if) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (:) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# frozenset is used to ensure hashability) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj 0 0 0 rg (key) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (frozenset) Tj 0 0 0 rg (\() Tj 0 0 0 rg (kw) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (items) Tj 0 0 0 rg (\(\)\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (else) Tj /F3 10 Tf 0 0 0 rg (:) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (key) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (args) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (cache) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (cache) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# attribute added by memoize) Tj /F3 10 Tf 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (if) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (key) Tj 0 0 0 rg ( ) Tj /F5 10 Tf .666667 .133333 1 rg (not) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F5 10 Tf .666667 .133333 1 rg (in) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (cache) Tj 0 0 0 rg (:) Tj 0 0 0 rg T* ( ) Tj 0 0 0 rg (cache) Tj 0 0 0 rg ([) Tj 0 0 0 rg (key) Tj 0 0 0 rg (]) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (func) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (cache) Tj 0 0 0 rg ([) Tj 0 0 0 rg (key) Tj 0 0 0 rg (]) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 172.6236 cm q 0 0 0 rg BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL 2.008221 Tw (We have avoided the need to name the first argument, so the problem simply disappears. This is a) Tj T* 0 Tw (technique that you should keep in mind when writing decorators for functions with keyword arguments.) Tj T* ET Q Q q 1 0 0 1 62.69291 142.6236 cm q BT 1 0 0 1 0 14 Tm 1.790488 Tw 12 TL /F1 10 Tf 0 0 0 rg (On a similar tone, there is a restriction on the names of the arguments: for instance, if try to call an) Tj T* 0 Tw (argument ) Tj /F3 10 Tf 0 0 0 rg (_call_ ) Tj /F1 10 Tf 0 0 0 rg (or ) Tj /F3 10 Tf 0 0 0 rg (_func_ ) Tj /F1 10 Tf 0 0 0 rg (you will get a ) Tj /F3 10 Tf 0 0 0 rg (NameError) Tj /F1 10 Tf 0 0 0 rg (:) Tj T* ET Q Q q 1 0 0 1 62.69291 85.42362 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 48 re B* Q q .960784 .960784 .862745 rg n 0 24 6 12 re f* .960784 .960784 .862745 rg n 6 24 6 12 re f* .960784 .960784 .862745 rg n 12 24 6 12 re f* .960784 .960784 .862745 rg n 24 24 36 12 re f* .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 24 12 18 12 re f* .960784 .960784 .862745 rg n 48 12 6 12 re f* .960784 .960784 .862745 rg n 54 12 6 12 re f* .960784 .960784 .862745 rg n 60 12 36 12 re f* .960784 .960784 .862745 rg n 96 12 12 12 re f* .960784 .960784 .862745 rg n 114 12 30 12 re f* .960784 .960784 .862745 rg n 144 12 6 12 re f* .960784 .960784 .862745 rg n 150 12 6 12 re f* .960784 .960784 .862745 rg n 156 12 6 12 re f* .960784 .960784 .862745 rg n 0 0 18 12 re f* BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj .666667 .133333 1 rg (@trace) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (f) Tj 0 0 0 rg (\() Tj 0 0 0 rg (_func_) Tj 0 0 0 rg (\):) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (print) Tj /F3 10 Tf 0 0 0 rg (\() Tj 0 0 0 rg (f) Tj 0 0 0 rg (\)) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg T* ET Q Q Q Q Q endstream endobj 124 0 obj << /Length 10448 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q 1 0 0 1 62.69291 691.8236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 72 re B* Q q .960784 .960784 .862745 rg n 0 48 54 12 re f* .960784 .960784 .862745 rg n 60 48 6 12 re f* .960784 .960784 .862745 rg n 66 48 24 12 re f* .960784 .960784 .862745 rg n 96 48 36 12 re f* .960784 .960784 .862745 rg n 138 48 24 12 re f* .960784 .960784 .862745 rg n 168 48 24 12 re f* .960784 .960784 .862745 rg n 192 48 12 12 re f* .960784 .960784 .862745 rg n 12 36 18 12 re f* .960784 .960784 .862745 rg n 0 24 54 12 re f* .960784 .960784 .862745 rg n 54 24 6 12 re f* .960784 .960784 .862745 rg n 66 24 36 12 re f* .960784 .960784 .862745 rg n 108 24 12 12 re f* .960784 .960784 .862745 rg n 126 24 60 12 re f* .960784 .960784 .862745 rg n 192 24 12 12 re f* .960784 .960784 .862745 rg n 0 12 18 12 re f* .960784 .960784 .862745 rg n 24 12 6 12 re f* .960784 .960784 .862745 rg n 30 12 6 12 re f* .960784 .960784 .862745 rg n 36 12 36 12 re f* .960784 .960784 .862745 rg n 72 12 12 12 re f* .960784 .960784 .862745 rg n 24 0 36 12 re f* .960784 .960784 .862745 rg n 66 0 36 12 re f* .960784 .960784 .862745 rg n 102 0 6 12 re f* .960784 .960784 .862745 rg n 108 0 36 12 re f* .960784 .960784 .862745 rg n 144 0 6 12 re f* .960784 .960784 .862745 rg n 156 0 36 12 re f* .960784 .960784 .862745 rg n 192 0 6 12 re f* BT 1 0 0 1 0 50 Tm 12 TL /F3 10 Tf 0 0 0 rg (Traceback) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (\() Tj 0 0 0 rg (most) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (recent) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (call) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (last) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj .4 .4 .4 rg (...) Tj 0 0 0 rg T* /F5 10 Tf .823529 .254902 .227451 rg (NameError) Tj /F3 10 Tf 0 0 0 rg (:) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (_func_) Tj 0 0 0 rg ( ) Tj /F5 10 Tf .666667 .133333 1 rg (is) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (overridden) Tj 0 0 0 rg ( ) Tj /F5 10 Tf .666667 .133333 1 rg (in) Tj /F3 10 Tf 0 0 0 rg T* /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (f) Tj 0 0 0 rg (\() Tj 0 0 0 rg (_func_) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf 0 .501961 0 rg (return) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (_call_) Tj 0 0 0 rg (\() Tj 0 0 0 rg (_func_) Tj 0 0 0 rg (,) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (_func_) Tj 0 0 0 rg (\)) Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 659.8236 cm q 0 0 0 rg BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL 1.720651 Tw (Finally, the implementation is such that the decorated function makes a \(shallow\) copy of the original) Tj T* 0 Tw (function dictionary:) Tj T* ET Q Q q 1 0 0 1 62.69291 506.6236 cm q q 1 0 0 1 0 0 cm q 1 0 0 1 6.6 6.6 cm q .662745 .662745 .662745 RG .5 w .960784 .960784 .862745 rg n -6 -6 468.6898 144 re B* Q q .960784 .960784 .862745 rg n 0 120 6 12 re f* .960784 .960784 .862745 rg n 6 120 6 12 re f* .960784 .960784 .862745 rg n 12 120 6 12 re f* .960784 .960784 .862745 rg n 24 120 18 12 re f* .960784 .960784 .862745 rg n 48 120 6 12 re f* .960784 .960784 .862745 rg n 54 120 18 12 re f* .960784 .960784 .862745 rg n 78 120 24 12 re f* .960784 .960784 .862745 rg n 108 120 138 12 re f* .960784 .960784 .862745 rg n 0 108 6 12 re f* .960784 .960784 .862745 rg n 6 108 6 12 re f* .960784 .960784 .862745 rg n 12 108 6 12 re f* .960784 .960784 .862745 rg n 24 108 6 12 re f* .960784 .960784 .862745 rg n 30 108 6 12 re f* .960784 .960784 .862745 rg n 36 108 30 12 re f* .960784 .960784 .862745 rg n 72 108 6 12 re f* .960784 .960784 .862745 rg n 84 108 66 12 re f* .960784 .960784 .862745 rg n 156 108 132 12 re f* .960784 .960784 .862745 rg n 0 96 6 12 re f* .960784 .960784 .862745 rg n 6 96 6 12 re f* .960784 .960784 .862745 rg n 12 96 6 12 re f* .960784 .960784 .862745 rg n 24 96 6 12 re f* .960784 .960784 .862745 rg n 30 96 6 12 re f* .960784 .960784 .862745 rg n 36 96 30 12 re f* .960784 .960784 .862745 rg n 72 96 6 12 re f* .960784 .960784 .862745 rg n 84 96 96 12 re f* .960784 .960784 .862745 rg n 186 96 162 12 re f* .960784 .960784 .862745 rg n 0 72 6 12 re f* .960784 .960784 .862745 rg n 6 72 6 12 re f* .960784 .960784 .862745 rg n 12 72 6 12 re f* .960784 .960784 .862745 rg n 24 72 48 12 re f* .960784 .960784 .862745 rg n 78 72 6 12 re f* .960784 .960784 .862745 rg n 90 72 30 12 re f* .960784 .960784 .862745 rg n 120 72 6 12 re f* .960784 .960784 .862745 rg n 126 72 6 12 re f* .960784 .960784 .862745 rg n 132 72 6 12 re f* .960784 .960784 .862745 rg n 144 72 144 12 re f* .960784 .960784 .862745 rg n 0 48 6 12 re f* .960784 .960784 .862745 rg n 6 48 6 12 re f* .960784 .960784 .862745 rg n 12 48 6 12 re f* .960784 .960784 .862745 rg n 24 48 48 12 re f* .960784 .960784 .862745 rg n 72 48 6 12 re f* .960784 .960784 .862745 rg n 78 48 30 12 re f* .960784 .960784 .862745 rg n 0 36 66 12 re f* .960784 .960784 .862745 rg n 0 24 6 12 re f* .960784 .960784 .862745 rg n 6 24 6 12 re f* .960784 .960784 .862745 rg n 12 24 6 12 re f* .960784 .960784 .862745 rg n 24 24 48 12 re f* .960784 .960784 .862745 rg n 72 24 6 12 re f* .960784 .960784 .862745 rg n 78 24 30 12 re f* .960784 .960784 .862745 rg n 114 24 6 12 re f* .960784 .960784 .862745 rg n 126 24 126 12 re f* .960784 .960784 .862745 rg n 258 24 84 12 re f* .960784 .960784 .862745 rg n 0 12 6 12 re f* .960784 .960784 .862745 rg n 6 12 6 12 re f* .960784 .960784 .862745 rg n 12 12 6 12 re f* .960784 .960784 .862745 rg n 24 12 6 12 re f* .960784 .960784 .862745 rg n 30 12 6 12 re f* .960784 .960784 .862745 rg n 36 12 30 12 re f* .960784 .960784 .862745 rg n 72 12 234 12 re f* .960784 .960784 .862745 rg n 0 0 96 12 re f* BT 1 0 0 1 0 122 Tm 12 TL /F3 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (def) Tj /F3 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (f) Tj 0 0 0 rg (\(\):) Tj 0 0 0 rg ( ) Tj /F5 10 Tf 0 .501961 0 rg (pass) Tj /F3 10 Tf 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# the original function) Tj /F3 10 Tf 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (attr1) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("something") Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# setting an attribute) Tj /F3 10 Tf 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (attr2) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("something else") Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# setting another attribute) Tj /F3 10 Tf 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (traced_f) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (trace) Tj 0 0 0 rg (\() Tj 0 0 0 rg (f) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# the decorated function) Tj /F3 10 Tf 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (traced_f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (attr1) Tj 0 0 0 rg T* .729412 .129412 .129412 rg ('something') Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (traced_f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (attr2) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("something different") Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# setting attr) Tj /F3 10 Tf 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (attr2) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# the original attribute did not change) Tj /F3 10 Tf 0 0 0 rg T* .729412 .129412 .129412 rg ('something else') Tj T* ET Q Q Q Q Q q 1 0 0 1 62.69291 473.6236 cm q BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (LICENSE) Tj T* ET Q Q q 1 0 0 1 62.69291 455.6236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Copyright \(c\) 2005-2015, Michele Simionato All rights reserved.) Tj T* ET Q Q q 1 0 0 1 62.69291 425.6236 cm q 0 0 0 rg BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL 1.328555 Tw (Redistribution and use in source and binary forms, with or without modification, are permitted provided) Tj T* 0 Tw (that the following conditions are met:) Tj T* ET Q Q q 1 0 0 1 62.69291 419.6236 cm Q q 1 0 0 1 62.69291 371.6236 cm 0 0 0 rg BT /F1 10 Tf 12 TL ET BT 1 0 0 1 0 2 Tm T* ET q 1 0 0 1 20 0 cm q 0 0 0 rg BT 1 0 0 1 0 38 Tm /F1 10 Tf 12 TL .830651 Tw (Redistributions of source code must retain the above copyright notice, this list of conditions and the) Tj T* 0 Tw .161647 Tw (following disclaimer. Redistributions in bytecode form must reproduce the above copyright notice, this) Tj T* 0 Tw 1.259213 Tw (list of conditions and the following disclaimer in the documentation and/or other materials provided) Tj T* 0 Tw (with the distribution.) Tj T* ET Q Q q Q Q q 1 0 0 1 62.69291 371.6236 cm Q q 1 0 0 1 62.69291 245.6236 cm q 0 0 0 rg BT 1 0 0 1 0 110 Tm /F1 10 Tf 12 TL .17998 Tw (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND) Tj T* 0 Tw 2.911797 Tw (ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED) Tj T* 0 Tw 5.165529 Tw (WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE) Tj T* 0 Tw 1.395433 Tw (DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE) Tj T* 0 Tw 5.53122 Tw (FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL) Tj T* 0 Tw 2.705976 Tw (DAMAGES \(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR) Tj T* 0 Tw 3.868976 Tw (SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION\) HOWEVER) Tj T* 0 Tw 1.326647 Tw (CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR) Tj T* 0 Tw 1.525366 Tw (TORT \(INCLUDING NEGLIGENCE OR OTHERWISE\) ARISING IN ANY WAY OUT OF THE USE OF) Tj T* 0 Tw (THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.) Tj T* ET Q Q q 1 0 0 1 62.69291 215.6236 cm q 0 0 0 rg BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .407132 Tw (If you use this software and you are happy with it, consider sending me a note, just to gratify my ego. On) Tj T* 0 Tw (the other hand, if you use this software and you are unhappy with it, send me a patch!) Tj T* ET Q Q endstream endobj 125 0 obj << /Nums [ 0 126 0 R 1 127 0 R 2 128 0 R 3 129 0 R 4 130 0 R 5 131 0 R 6 132 0 R 7 133 0 R 8 134 0 R 9 135 0 R 10 136 0 R 11 137 0 R 12 138 0 R 13 139 0 R 14 140 0 R 15 141 0 R 16 142 0 R 17 143 0 R 18 144 0 R 19 145 0 R 20 146 0 R ] >> endobj 126 0 obj << /S /D /St 1 >> endobj 127 0 obj << /S /D /St 2 >> endobj 128 0 obj << /S /D /St 3 >> endobj 129 0 obj << /S /D /St 4 >> endobj 130 0 obj << /S /D /St 5 >> endobj 131 0 obj << /S /D /St 6 >> endobj 132 0 obj << /S /D /St 7 >> endobj 133 0 obj << /S /D /St 8 >> endobj 134 0 obj << /S /D /St 9 >> endobj 135 0 obj << /S /D /St 10 >> endobj 136 0 obj << /S /D /St 11 >> endobj 137 0 obj << /S /D /St 12 >> endobj 138 0 obj << /S /D /St 13 >> endobj 139 0 obj << /S /D /St 14 >> endobj 140 0 obj << /S /D /St 15 >> endobj 141 0 obj << /S /D /St 16 >> endobj 142 0 obj << /S /D /St 17 >> endobj 143 0 obj << /S /D /St 18 >> endobj 144 0 obj << /S /D /St 19 >> endobj 145 0 obj << /S /D /St 20 >> endobj 146 0 obj << /S /D /St 21 >> endobj xref 0 147 0000000000 65535 f 0000000075 00000 n 0000000162 00000 n 0000000272 00000 n 0000000387 00000 n 0000000495 00000 n 0000000684 00000 n 0000000882 00000 n 0000001053 00000 n 0000001224 00000 n 0000001395 00000 n 0000001567 00000 n 0000001739 00000 n 0000001911 00000 n 0000002083 00000 n 0000002255 00000 n 0000002427 00000 n 0000002599 00000 n 0000002771 00000 n 0000002943 00000 n 0000003115 00000 n 0000003287 00000 n 0000003459 00000 n 0000003631 00000 n 0000003803 00000 n 0000003975 00000 n 0000004147 00000 n 0000004319 00000 n 0000004491 00000 n 0000004663 00000 n 0000004835 00000 n 0000005007 00000 n 0000005179 00000 n 0000005351 00000 n 0000005523 00000 n 0000005695 00000 n 0000005867 00000 n 0000006039 00000 n 0000006211 00000 n 0000006383 00000 n 0000006555 00000 n 0000006727 00000 n 0000006899 00000 n 0000007071 00000 n 0000007243 00000 n 0000007415 00000 n 0000007587 00000 n 0000007759 00000 n 0000007931 00000 n 0000008103 00000 n 0000008646 00000 n 0000008765 00000 n 0000008945 00000 n 0000009176 00000 n 0000009381 00000 n 0000009495 00000 n 0000009612 00000 n 0000009841 00000 n 0000010079 00000 n 0000010291 00000 n 0000010503 00000 n 0000010699 00000 n 0000010930 00000 n 0000011142 00000 n 0000011354 00000 n 0000011566 00000 n 0000011778 00000 n 0000011969 00000 n 0000012200 00000 n 0000012418 00000 n 0000012649 00000 n 0000012861 00000 n 0000013073 00000 n 0000013285 00000 n 0000013475 00000 n 0000013665 00000 n 0000013903 00000 n 0000014115 00000 n 0000014327 00000 n 0000014539 00000 n 0000014751 00000 n 0000014963 00000 n 0000015074 00000 n 0000015322 00000 n 0000015401 00000 n 0000015518 00000 n 0000015646 00000 n 0000015788 00000 n 0000015917 00000 n 0000016059 00000 n 0000016189 00000 n 0000016324 00000 n 0000016462 00000 n 0000016599 00000 n 0000016725 00000 n 0000016859 00000 n 0000016991 00000 n 0000017132 00000 n 0000017273 00000 n 0000017426 00000 n 0000017562 00000 n 0000017721 00000 n 0000017865 00000 n 0000017979 00000 n 0000018193 00000 n 0000025814 00000 n 0000033097 00000 n 0000045722 00000 n 0000061060 00000 n 0000078829 00000 n 0000099174 00000 n 0000115828 00000 n 0000134508 00000 n 0000152994 00000 n 0000167532 00000 n 0000186263 00000 n 0000201638 00000 n 0000214765 00000 n 0000230505 00000 n 0000245810 00000 n 0000257327 00000 n 0000270757 00000 n 0000285120 00000 n 0000294813 00000 n 0000310292 00000 n 0000320799 00000 n 0000321072 00000 n 0000321110 00000 n 0000321148 00000 n 0000321186 00000 n 0000321224 00000 n 0000321262 00000 n 0000321300 00000 n 0000321338 00000 n 0000321376 00000 n 0000321414 00000 n 0000321453 00000 n 0000321492 00000 n 0000321531 00000 n 0000321570 00000 n 0000321609 00000 n 0000321648 00000 n 0000321687 00000 n 0000321726 00000 n 0000321765 00000 n 0000321804 00000 n 0000321843 00000 n trailer << /ID % ReportLab generated PDF document -- digest (http://www.reportlab.com) [(\344\271\334\024\243\366\306\346\246\010\347/\245\002\314\236) (\344\271\334\024\243\366\306\346\246\010\347/\245\002\314\236)] /Info 82 0 R /Root 81 0 R /Size 147 >> startxref 321882 %%EOF