summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichele Simionato <michele.simionato@gmail.com>2012-10-18 10:50:25 +0200
committerMichele Simionato <michele.simionato@gmail.com>2012-10-18 10:50:25 +0200
commitc5695032e433a85586c44568b1bbe1d64953eb61 (patch)
tree7c03705b35098a1219f262512f5be161f3917987
parenta826b9a2f7e40a7948da1b351d169fef87625bbc (diff)
parentebc8ff5064dc649116047856a44c43853d8cdcd6 (diff)
downloadmicheles-c5695032e433a85586c44568b1bbe1d64953eb61.tar.gz
Merged devel branch for decorator 3.4decorator-3.4.0
-rw-r--r--decorator/CHANGES.txt4
-rw-r--r--decorator/Makefile8
-rw-r--r--decorator/documentation.html485
-rw-r--r--decorator/documentation.pdf1603
-rw-r--r--decorator/documentation.py130
-rw-r--r--decorator/documentation3.html164
-rw-r--r--decorator/documentation3.pdf1717
-rw-r--r--decorator/documentation3.py159
-rw-r--r--decorator/index.html12
-rw-r--r--decorator/src/decorator.py99
10 files changed, 2512 insertions, 1869 deletions
diff --git a/decorator/CHANGES.txt b/decorator/CHANGES.txt
index a319a94..bb093fa 100644
--- a/decorator/CHANGES.txt
+++ b/decorator/CHANGES.txt
@@ -1,6 +1,10 @@
HISTORY
----------
+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
diff --git a/decorator/Makefile b/decorator/Makefile
index 7987755..a5c0b86 100644
--- a/decorator/Makefile
+++ b/decorator/Makefile
@@ -1,8 +1,8 @@
-RST=python $(HOME)/trunk/ROnline/RCommon/Python/ms/tools/rst.py
+RST=python $(S)/ms/tools/rst.py
rst: documentation.py documentation3.py
- python $(HOME)/trunk/ROnline/RCommon/Python/ms/tools/minidoc.py -d documentation.py
- python3 $(S)/minidoc3.py -d documentation3.py
+ python $(S)/ms/tools/minidoc.py -d documentation.py
+ python3.3 $(S)/minidoc3.py -d documentation3.py
html: /tmp/documentation.rst /tmp/documentation3.rst
$(RST) /tmp/documentation.rst
@@ -15,4 +15,4 @@ pdf: /tmp/documentation.rst /tmp/documentation3.rst
cp /tmp/documentation.html /tmp/documentation3.html .
upload: documentation.pdf documentation3.pdf
- python3 setup.py register sdist upload
+ python3.3 setup.py register sdist upload
diff --git a/decorator/documentation.html b/decorator/documentation.html
index 4fb7fc8..25a5709 100644
--- a/decorator/documentation.html
+++ b/decorator/documentation.html
@@ -3,7 +3,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="generator" content="Docutils 0.7: http://docutils.sourceforge.net/" />
+<meta name="generator" content="Docutils 0.8.1: http://docutils.sourceforge.net/" />
<title>The decorator module</title>
<meta name="author" content="Michele Simionato" />
<style type="text/css">
@@ -83,10 +83,10 @@
<tr class="field"><th class="docinfo-name">E-mail:</th><td class="field-body"><a class="reference external" href="mailto:michele.simionato&#64;gmail.com">michele.simionato&#64;gmail.com</a></td>
</tr>
<tr><th class="docinfo-name">Version:</th>
-<td>3.3.2 (2011-11-09)</td></tr>
+<td>3.4.0 (2012-10-18)</td></tr>
<tr class="field"><th class="docinfo-name">Requires:</th><td class="field-body">Python 2.4+</td>
</tr>
-<tr class="field"><th class="docinfo-name">Download page:</th><td class="field-body"><a class="reference external" href="http://pypi.python.org/pypi/decorator/3.3.2">http://pypi.python.org/pypi/decorator/3.3.2</a></td>
+<tr class="field"><th class="docinfo-name">Download page:</th><td class="field-body"><a class="reference external" href="http://pypi.python.org/pypi/decorator/3.4.0">http://pypi.python.org/pypi/decorator/3.4.0</a></td>
</tr>
<tr class="field"><th class="docinfo-name">Installation:</th><td class="field-body"><tt class="docutils literal">easy_install decorator</tt></td>
</tr>
@@ -105,12 +105,13 @@
<li><a class="reference internal" href="#decorator-is-a-decorator" id="id8"><tt class="docutils literal">decorator</tt> is a decorator</a></li>
<li><a class="reference internal" href="#blocking" id="id9"><tt class="docutils literal">blocking</tt></a></li>
<li><a class="reference internal" href="#async" id="id10"><tt class="docutils literal">async</tt></a></li>
-<li><a class="reference internal" href="#the-functionmaker-class" id="id11">The <tt class="docutils literal">FunctionMaker</tt> class</a></li>
-<li><a class="reference internal" href="#getting-the-source-code" id="id12">Getting the source code</a></li>
-<li><a class="reference internal" href="#dealing-with-third-party-decorators" id="id13">Dealing with third party decorators</a></li>
-<li><a class="reference internal" href="#caveats-and-limitations" id="id14">Caveats and limitations</a></li>
-<li><a class="reference internal" href="#compatibility-notes" id="id15">Compatibility notes</a></li>
-<li><a class="reference internal" href="#licence" id="id16">LICENCE</a></li>
+<li><a class="reference internal" href="#contextmanager" id="id11">contextmanager</a></li>
+<li><a class="reference internal" href="#the-functionmaker-class" id="id12">The <tt class="docutils literal">FunctionMaker</tt> class</a></li>
+<li><a class="reference internal" href="#getting-the-source-code" id="id13">Getting the source code</a></li>
+<li><a class="reference internal" href="#dealing-with-third-party-decorators" id="id14">Dealing with third party decorators</a></li>
+<li><a class="reference internal" href="#caveats-and-limitations" id="id15">Caveats and limitations</a></li>
+<li><a class="reference internal" href="#compatibility-notes" id="id16">Compatibility notes</a></li>
+<li><a class="reference internal" href="#licence" id="id17">LICENCE</a></li>
</ul>
</div>
<div class="section" id="introduction">
@@ -179,22 +180,24 @@ but they do not preserve the signature.
A simple implementation could be the following (notice
that in general it is impossible to memoize correctly something
that depends on non-hashable arguments):</p>
-<pre class="literal-block">
-def memoize_uw(func):
- func.cache = {}
- def memoize(*args, **kw):
- if kw: # frozenset is used to ensure hashability
- key = args, frozenset(kw.iteritems())
- else:
- key = args
- cache = func.cache
- if key in cache:
- return cache[key]
- else:
- cache[key] = result = func(*args, **kw)
- return result
- return functools.update_wrapper(memoize, func)
-</pre>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="k">def</span> <span class="nf">memoize_uw</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
+ <span class="n">func</span><span class="o">.</span><span class="n">cache</span> <span class="o">=</span> <span class="p">{}</span>
+ <span class="k">def</span> <span class="nf">memoize</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
+ <span class="k">if</span> <span class="n">kw</span><span class="p">:</span> <span class="c"># frozenset is used to ensure hashability</span>
+ <span class="n">key</span> <span class="o">=</span> <span class="n">args</span><span class="p">,</span> <span class="nb">frozenset</span><span class="p">(</span><span class="n">kw</span><span class="o">.</span><span class="n">iteritems</span><span class="p">())</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">key</span> <span class="o">=</span> <span class="n">args</span>
+ <span class="n">cache</span> <span class="o">=</span> <span class="n">func</span><span class="o">.</span><span class="n">cache</span>
+ <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">cache</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">cache</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">cache</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">result</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">result</span>
+ <span class="k">return</span> <span class="n">functools</span><span class="o">.</span><span class="n">update_wrapper</span><span class="p">(</span><span class="n">memoize</span><span class="p">,</span> <span class="n">func</span><span class="p">)</span>
+</pre></div>
+
+</div>
<p>Here we used the <a class="reference external" href="http://www.python.org/doc/2.5.2/lib/module-functools.html">functools.update_wrapper</a> 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
@@ -255,25 +258,29 @@ returns the decorated function. The caller function must have
signature <tt class="docutils literal">(f, *args, **kw)</tt> and it must call the original function <tt class="docutils literal">f</tt>
with arguments <tt class="docutils literal">args</tt> and <tt class="docutils literal">kw</tt>, implementing the wanted capability,
i.e. memoization in this case:</p>
-<pre class="literal-block">
-def _memoize(func, *args, **kw):
- if kw: # frozenset is used to ensure hashability
- key = args, frozenset(kw.iteritems())
- else:
- key = args
- cache = func.cache # attributed added by memoize
- if key in cache:
- return cache[key]
- else:
- cache[key] = result = func(*args, **kw)
- return result
-</pre>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="k">def</span> <span class="nf">_memoize</span><span class="p">(</span><span class="n">func</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
+ <span class="k">if</span> <span class="n">kw</span><span class="p">:</span> <span class="c"># frozenset is used to ensure hashability</span>
+ <span class="n">key</span> <span class="o">=</span> <span class="n">args</span><span class="p">,</span> <span class="nb">frozenset</span><span class="p">(</span><span class="n">kw</span><span class="o">.</span><span class="n">iteritems</span><span class="p">())</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">key</span> <span class="o">=</span> <span class="n">args</span>
+ <span class="n">cache</span> <span class="o">=</span> <span class="n">func</span><span class="o">.</span><span class="n">cache</span> <span class="c"># attributed added by memoize</span>
+ <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">cache</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">cache</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">cache</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">result</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">result</span>
+</pre></div>
+
+</div>
<p>At this point you can define your decorator as follows:</p>
-<pre class="literal-block">
-def memoize(f):
- f.cache = {}
- return decorator(_memoize, f)
-</pre>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="k">def</span> <span class="nf">memoize</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
+ <span class="n">f</span><span class="o">.</span><span class="n">cache</span> <span class="o">=</span> <span class="p">{}</span>
+ <span class="k">return</span> <span class="n">decorator</span><span class="p">(</span><span class="n">_memoize</span><span class="p">,</span> <span class="n">f</span><span class="p">)</span>
+</pre></div>
+
+</div>
<p>The difference with respect to the <tt class="docutils literal">memoize_uw</tt> approach, which is based
on nested functions, is that the decorator module forces you to lift
the inner function at the outer level (<em>flat is better than nested</em>).
@@ -307,15 +314,19 @@ decorate to the caller function.</p>
<p>As an additional example, here is how you can define a trivial
<tt class="docutils literal">trace</tt> decorator, which prints a message everytime the traced
function is called:</p>
-<pre class="literal-block">
-def _trace(f, *args, **kw):
- print &quot;calling %s with args %s, %s&quot; % (f.__name__, args, kw)
- return f(*args, **kw)
-</pre>
-<pre class="literal-block">
-def trace(f):
- return decorator(_trace, f)
-</pre>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="k">def</span> <span class="nf">_trace</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
+ <span class="k">print</span> <span class="s">&quot;calling </span><span class="si">%s</span><span class="s"> with args </span><span class="si">%s</span><span class="s">, </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">__name__</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kw</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">f</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>
+</pre></div>
+
+</div>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="k">def</span> <span class="nf">trace</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
+ <span class="k">return</span> <span class="n">decorator</span><span class="p">(</span><span class="n">_trace</span><span class="p">,</span> <span class="n">f</span><span class="p">)</span>
+</pre></div>
+
+</div>
<p>Here is an example of usage:</p>
<div class="codeblock python">
<div class="highlight"><pre><span class="o">&gt;&gt;&gt;</span> <span class="nd">@trace</span>
@@ -419,21 +430,23 @@ object which can be used as a decorator:</p>
sometimes it is best to have back a &quot;busy&quot; message than to block everything.
This behavior can be implemented with a suitable family of decorators,
where the parameter is the busy message:</p>
-<pre class="literal-block">
-def blocking(not_avail):
- def blocking(f, *args, **kw):
- if not hasattr(f, &quot;thread&quot;): # 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)
-</pre>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="k">def</span> <span class="nf">blocking</span><span class="p">(</span><span class="n">not_avail</span><span class="p">):</span>
+ <span class="k">def</span> <span class="nf">blocking</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="s">&quot;thread&quot;</span><span class="p">):</span> <span class="c"># no thread running</span>
+ <span class="k">def</span> <span class="nf">set_result</span><span class="p">():</span> <span class="n">f</span><span class="o">.</span><span class="n">result</span> <span class="o">=</span> <span class="n">f</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>
+ <span class="n">f</span><span class="o">.</span><span class="n">thread</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">(</span><span class="bp">None</span><span class="p">,</span> <span class="n">set_result</span><span class="p">)</span>
+ <span class="n">f</span><span class="o">.</span><span class="n">thread</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
+ <span class="k">return</span> <span class="n">not_avail</span>
+ <span class="k">elif</span> <span class="n">f</span><span class="o">.</span><span class="n">thread</span><span class="o">.</span><span class="n">isAlive</span><span class="p">():</span>
+ <span class="k">return</span> <span class="n">not_avail</span>
+ <span class="k">else</span><span class="p">:</span> <span class="c"># the thread is ended, return the stored result</span>
+ <span class="k">del</span> <span class="n">f</span><span class="o">.</span><span class="n">thread</span>
+ <span class="k">return</span> <span class="n">f</span><span class="o">.</span><span class="n">result</span>
+ <span class="k">return</span> <span class="n">decorator</span><span class="p">(</span><span class="n">blocking</span><span class="p">)</span>
+</pre></div>
+
+</div>
<p>Functions decorated with <tt class="docutils literal">blocking</tt> will return a busy message if
the resource is unavailable, and the intended result if the resource is
available. For instance:</p>
@@ -467,69 +480,74 @@ available. For instance:</p>
implemented as a function returning a decorator.
For more complex situations, it is more
convenient to implement decorator factories as classes returning
-callable objects that can be used as signature-preserving
-decorators. The suggested pattern to do that is to introduce
-a helper method <tt class="docutils literal">call(self, func, *args, **kw)</tt> and to call
-it in the <tt class="docutils literal">__call__(self, func)</tt> method.</p>
-<p>As an example, here I show a decorator
+callable objects that can be converted into decorators.</p>
+<p>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. Moreover, it is possible to set
three callbacks <tt class="docutils literal">on_success</tt>, <tt class="docutils literal">on_failure</tt> and <tt class="docutils literal">on_closing</tt>,
-to specify how to manage the function call.
-The implementation is the following:</p>
-<pre class="literal-block">
-def on_success(result): # default implementation
- &quot;Called on the result of the function&quot;
- return result
-</pre>
-<pre class="literal-block">
-def on_failure(exc_info): # default implementation
- &quot;Called if the function fails&quot;
- pass
-</pre>
-<pre class="literal-block">
-def on_closing(): # default implementation
- &quot;Called at the end, both in case of success and failure&quot;
- pass
-</pre>
-<pre class="literal-block">
-class Async(object):
- &quot;&quot;&quot;
- A decorator converting blocking functions into asynchronous
- functions, by using threads or processes. Examples:
-
- async_with_threads = Async(threading.Thread)
- async_with_processes = Async(multiprocessing.Process)
- &quot;&quot;&quot;
-
- def __init__(self, threadfactory):
- self.threadfactory = threadfactory
-
- def __call__(self, func, on_success=on_success,
- on_failure=on_failure, on_closing=on_closing):
- # every decorated function has its own independent thread counter
- func.counter = itertools.count(1)
- func.on_success = on_success
- func.on_failure = on_failure
- func.on_closing = on_closing
- return decorator(self.call, func)
-
- def call(self, func, *args, **kw):
- def func_wrapper():
- try:
- result = func(*args, **kw)
- except:
- func.on_failure(sys.exc_info())
- else:
- return func.on_success(result)
- finally:
- func.on_closing()
- name = '%s-%s' % (func.__name__, func.counter.next())
- thread = self.threadfactory(None, func_wrapper, name)
- thread.start()
- return thread
-</pre>
+to specify how to manage the function call (of course the code here
+is just an example, it is not a recommended way of doing multi-threaded
+programming). The implementation is the following:</p>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="k">def</span> <span class="nf">on_success</span><span class="p">(</span><span class="n">result</span><span class="p">):</span> <span class="c"># default implementation</span>
+ <span class="s">&quot;Called on the result of the function&quot;</span>
+ <span class="k">return</span> <span class="n">result</span>
+</pre></div>
+
+</div>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="k">def</span> <span class="nf">on_failure</span><span class="p">(</span><span class="n">exc_info</span><span class="p">):</span> <span class="c"># default implementation</span>
+ <span class="s">&quot;Called if the function fails&quot;</span>
+ <span class="k">pass</span>
+</pre></div>
+
+</div>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="k">def</span> <span class="nf">on_closing</span><span class="p">():</span> <span class="c"># default implementation</span>
+ <span class="s">&quot;Called at the end, both in case of success and failure&quot;</span>
+ <span class="k">pass</span>
+</pre></div>
+
+</div>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="k">class</span> <span class="nc">Async</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
+ <span class="sd">&quot;&quot;&quot;</span>
+<span class="sd"> A decorator converting blocking functions into asynchronous</span>
+<span class="sd"> functions, by using threads or processes. Examples:</span>
+
+<span class="sd"> async_with_threads = Async(threading.Thread)</span>
+<span class="sd"> async_with_processes = Async(multiprocessing.Process)</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+
+ <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">threadfactory</span><span class="p">,</span> <span class="n">on_success</span><span class="o">=</span><span class="n">on_success</span><span class="p">,</span>
+ <span class="n">on_failure</span><span class="o">=</span><span class="n">on_failure</span><span class="p">,</span> <span class="n">on_closing</span><span class="o">=</span><span class="n">on_closing</span><span class="p">):</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">threadfactory</span> <span class="o">=</span> <span class="n">threadfactory</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">on_success</span> <span class="o">=</span> <span class="n">on_success</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">on_failure</span> <span class="o">=</span> <span class="n">on_failure</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">on_closing</span> <span class="o">=</span> <span class="n">on_closing</span>
+
+ <span class="k">def</span> <span class="nf">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">func</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">counter</span> <span class="o">=</span> <span class="n">func</span><span class="o">.</span><span class="n">counter</span>
+ <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span> <span class="c"># instantiate the counter at the first call</span>
+ <span class="n">counter</span> <span class="o">=</span> <span class="n">func</span><span class="o">.</span><span class="n">counter</span> <span class="o">=</span> <span class="n">itertools</span><span class="o">.</span><span class="n">count</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
+ <span class="n">name</span> <span class="o">=</span> <span class="s">&#39;</span><span class="si">%s</span><span class="s">-</span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">func</span><span class="o">.</span><span class="n">__name__</span><span class="p">,</span> <span class="n">counter</span><span class="o">.</span><span class="n">next</span><span class="p">())</span>
+ <span class="k">def</span> <span class="nf">func_wrapper</span><span class="p">():</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">result</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>
+ <span class="k">except</span><span class="p">:</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">on_failure</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">exc_info</span><span class="p">())</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">on_success</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
+ <span class="k">finally</span><span class="p">:</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">on_closing</span><span class="p">()</span>
+ <span class="n">thread</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">threadfactory</span><span class="p">(</span><span class="bp">None</span><span class="p">,</span> <span class="n">func_wrapper</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
+ <span class="n">thread</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
+ <span class="k">return</span> <span class="n">thread</span>
+</pre></div>
+
+</div>
<p>The decorated function returns
the current execution thread, which can be stored and checked later, for
instance to verify that the thread <tt class="docutils literal">.isAlive()</tt>.</p>
@@ -538,7 +556,7 @@ an external resource which can be accessed by a single user at once
(for instance a printer). Then the access to the writing function must
be locked. Here is a minimalistic example:</p>
<div class="codeblock python">
-<div class="highlight"><pre><span class="o">&gt;&gt;&gt;</span> <span class="n">async</span> <span class="o">=</span> <span class="n">Async</span><span class="p">(</span><span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">)</span>
+<div class="highlight"><pre><span class="o">&gt;&gt;&gt;</span> <span class="n">async</span> <span class="o">=</span> <span class="n">decorator</span><span class="p">(</span><span class="n">Async</span><span class="p">(</span><span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">))</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">datalist</span> <span class="o">=</span> <span class="p">[]</span> <span class="c"># for simplicity the written data are stored into a list.</span>
@@ -571,8 +589,71 @@ be no synchronization problems since <tt class="docutils literal">write</tt> is
</div>
</div>
+<div class="section" id="contextmanager">
+<h1><a class="toc-backref" href="#id11">contextmanager</a></h1>
+<p>For a long time Python had in its standard library a <tt class="docutils literal">contextmanager</tt>
+decorator, able to convert generator functions into <tt class="docutils literal">GeneratorContextManager</tt>
+factories. For instance if you write</p>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">contextlib</span> <span class="kn">import</span> <span class="n">contextmanager</span>
+<span class="o">&gt;&gt;&gt;</span> <span class="nd">@contextmanager</span>
+<span class="o">...</span> <span class="k">def</span> <span class="nf">before_after</span><span class="p">(</span><span class="n">before</span><span class="p">,</span> <span class="n">after</span><span class="p">):</span>
+<span class="o">...</span> <span class="k">print</span><span class="p">(</span><span class="n">before</span><span class="p">)</span>
+<span class="o">...</span> <span class="k">yield</span>
+<span class="o">...</span> <span class="k">print</span><span class="p">(</span><span class="n">after</span><span class="p">)</span>
+</pre></div>
+
+</div>
+<p>then <tt class="docutils literal">before_after</tt> is a factory function returning
+<tt class="docutils literal">GeneratorContextManager</tt> objects which can be used with
+the <tt class="docutils literal">with</tt> statement:</p>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="o">&gt;&gt;&gt;</span> <span class="n">ba</span> <span class="o">=</span> <span class="n">before_after</span><span class="p">(</span><span class="s">&#39;BEFORE&#39;</span><span class="p">,</span> <span class="s">&#39;AFTER&#39;</span><span class="p">)</span>
+<span class="o">&gt;&gt;&gt;</span> <span class="nb">type</span><span class="p">(</span><span class="n">ba</span><span class="p">)</span>
+<span class="o">&lt;</span><span class="k">class</span> <span class="err">&#39;</span><span class="nc">contextlib</span><span class="o">.</span><span class="n">GeneratorContextManager</span><span class="s">&#39;&gt;</span>
+<span class="o">&gt;&gt;&gt;</span> <span class="k">with</span> <span class="n">ba</span><span class="p">:</span>
+<span class="o">...</span> <span class="k">print</span> <span class="s">&#39;hello&#39;</span>
+<span class="n">BEFORE</span>
+<span class="n">hello</span>
+<span class="n">AFTER</span>
+</pre></div>
+
+</div>
+<p>Basically, it is as if the content of the <tt class="docutils literal">with</tt> block was executed
+in the place of the <tt class="docutils literal">yield</tt> expression in the generator function.
+In Python 3.2 <tt class="docutils literal">GeneratorContextManager</tt>
+objects were enhanced with a <tt class="docutils literal">__call__</tt>
+method, so that they can be used as decorators as in this example:</p>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="o">&gt;&gt;&gt;</span> <span class="nd">@ba</span>
+<span class="o">...</span> <span class="k">def</span> <span class="nf">hello</span><span class="p">():</span>
+<span class="o">...</span> <span class="k">print</span> <span class="s">&#39;hello&#39;</span>
+<span class="o">...</span>
+<span class="o">&gt;&gt;&gt;</span> <span class="n">hello</span><span class="p">()</span>
+<span class="n">BEFORE</span>
+<span class="n">hello</span>
+<span class="n">AFTER</span>
+</pre></div>
+
+</div>
+<p>The <tt class="docutils literal">ba</tt> decorator is basically inserting a <tt class="docutils literal">with ba:</tt>
+block inside the function.
+However there two issues: the first is that <tt class="docutils literal">GeneratorContextManager</tt>
+objects are callable only in Python 3.2, so the previous example will break
+in older versions of Python; the second is that
+<tt class="docutils literal">GeneratorContextManager</tt> objects do not preserve the signature
+of the decorated functions: the decorated <tt class="docutils literal">hello</tt> function here will have
+a generic signature <tt class="docutils literal"><span class="pre">hello(*args,</span> **kwargs)</tt> but will break when
+called with more than zero arguments. For such reasons the decorator
+module, starting with release 3.4, offers a <tt class="docutils literal">decorator.contextmanager</tt>
+decorator that solves both problems and works even in Python 2.5.
+The usage is the same and factories decorated with <tt class="docutils literal">decorator.contextmanager</tt>
+will returns instances of <tt class="docutils literal">ContextManager</tt>, a subclass of
+<tt class="docutils literal">contextlib.GeneratorContextManager</tt> with a <tt class="docutils literal">__call__</tt> method
+acting as a signature-preserving decorator.</p>
+</div>
<div class="section" id="the-functionmaker-class">
-<h1><a class="toc-backref" href="#id11">The <tt class="docutils literal">FunctionMaker</tt> class</a></h1>
+<h1><a class="toc-backref" href="#id12">The <tt class="docutils literal">FunctionMaker</tt> class</a></h1>
<p>You may wonder about how the functionality of the <tt class="docutils literal">decorator</tt> module
is implemented. The basic building block is
a <tt class="docutils literal">FunctionMaker</tt> class which is able to generate on the fly
@@ -644,7 +725,7 @@ On the other hand, the functionality provided by
stay there forever.</p>
</div>
<div class="section" id="getting-the-source-code">
-<h1><a class="toc-backref" href="#id12">Getting the source code</a></h1>
+<h1><a class="toc-backref" href="#id13">Getting the source code</a></h1>
<p>Internally <tt class="docutils literal">FunctionMaker.create</tt> uses <tt class="docutils literal">exec</tt> to generate the
decorated function. Therefore
<tt class="docutils literal">inspect.getsource</tt> will not work for decorated functions. That
@@ -654,12 +735,14 @@ available</tt>. In the past I have considered this acceptable, since
<tt class="docutils literal">inspect.getsource</tt> does not really work even with regular
decorators. In that case <tt class="docutils literal">inspect.getsource</tt> gives you the wrapper
source code which is probably not what you want:</p>
-<pre class="literal-block">
-def identity_dec(func):
- def wrapper(*args, **kw):
- return func(*args, **kw)
- return wrapper
-</pre>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="k">def</span> <span class="nf">identity_dec</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
+ <span class="k">def</span> <span class="nf">wrapper</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
+ <span class="k">return</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">wrapper</span>
+</pre></div>
+
+</div>
<div class="codeblock python">
<div class="highlight"><pre><span class="nd">@identity_dec</span>
<span class="k">def</span> <span class="nf">example</span><span class="p">():</span> <span class="k">pass</span>
@@ -691,23 +774,25 @@ undecorated function:</p>
</div>
</div>
<div class="section" id="dealing-with-third-party-decorators">
-<h1><a class="toc-backref" href="#id13">Dealing with third party decorators</a></h1>
+<h1><a class="toc-backref" href="#id14">Dealing with third party decorators</a></h1>
<p>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 <tt class="docutils literal">decorator</tt>. You can use a
<tt class="docutils literal">FunctionMaker</tt> to implement that functionality as follows:</p>
-<pre class="literal-block">
-def decorator_apply(dec, func):
- &quot;&quot;&quot;
- Decorate a function by preserving the signature even if dec
- is not a signature-preserving decorator.
- &quot;&quot;&quot;
- return FunctionMaker.create(
- func, 'return decorated(%(signature)s)',
- dict(decorated=dec(func)), __wrapped__=func)
-</pre>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="k">def</span> <span class="nf">decorator_apply</span><span class="p">(</span><span class="n">dec</span><span class="p">,</span> <span class="n">func</span><span class="p">):</span>
+ <span class="sd">&quot;&quot;&quot;</span>
+<span class="sd"> Decorate a function by preserving the signature even if dec</span>
+<span class="sd"> is not a signature-preserving decorator.</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="k">return</span> <span class="n">FunctionMaker</span><span class="o">.</span><span class="n">create</span><span class="p">(</span>
+ <span class="n">func</span><span class="p">,</span> <span class="s">&#39;return decorated(</span><span class="si">%(signature)s</span><span class="s">)&#39;</span><span class="p">,</span>
+ <span class="nb">dict</span><span class="p">(</span><span class="n">decorated</span><span class="o">=</span><span class="n">dec</span><span class="p">(</span><span class="n">func</span><span class="p">)),</span> <span class="n">__wrapped__</span><span class="o">=</span><span class="n">func</span><span class="p">)</span>
+</pre></div>
+
+</div>
<p><tt class="docutils literal">decorator_apply</tt> sets the attribute <tt class="docutils literal">.__wrapped__</tt> of the generated
function to the original function, so that you can get the right
source code.</p>
@@ -721,51 +806,57 @@ 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,
<a class="reference external" href="http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496691">http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496691</a>.</p>
-<pre class="literal-block">
-class TailRecursive(object):
- &quot;&quot;&quot;
- 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.
- &quot;&quot;&quot;
-
- 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
-</pre>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="k">class</span> <span class="nc">TailRecursive</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
+ <span class="sd">&quot;&quot;&quot;</span>
+<span class="sd"> tail_recursive decorator based on Kay Schluehr&#39;s recipe</span>
+<span class="sd"> http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496691</span>
+<span class="sd"> with improvements by me and George Sakkis.</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+
+ <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">func</span><span class="p">):</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">func</span> <span class="o">=</span> <span class="n">func</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">firstcall</span> <span class="o">=</span> <span class="bp">True</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">CONTINUE</span> <span class="o">=</span> <span class="nb">object</span><span class="p">()</span> <span class="c"># sentinel</span>
+
+ <span class="k">def</span> <span class="nf">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwd</span><span class="p">):</span>
+ <span class="n">CONTINUE</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">CONTINUE</span>
+ <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">firstcall</span><span class="p">:</span>
+ <span class="n">func</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">func</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">firstcall</span> <span class="o">=</span> <span class="bp">False</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
+ <span class="n">result</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwd</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">result</span> <span class="ow">is</span> <span class="n">CONTINUE</span><span class="p">:</span> <span class="c"># update arguments</span>
+ <span class="n">args</span><span class="p">,</span> <span class="n">kwd</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">argskwd</span>
+ <span class="k">else</span><span class="p">:</span> <span class="c"># last call</span>
+ <span class="k">return</span> <span class="n">result</span>
+ <span class="k">finally</span><span class="p">:</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">firstcall</span> <span class="o">=</span> <span class="bp">True</span>
+ <span class="k">else</span><span class="p">:</span> <span class="c"># return the arguments of the tail call</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">argskwd</span> <span class="o">=</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwd</span>
+ <span class="k">return</span> <span class="n">CONTINUE</span>
+</pre></div>
+
+</div>
<p>Here the decorator is implemented as a class returning callable
objects.</p>
-<pre class="literal-block">
-def tail_recursive(func):
- return decorator_apply(TailRecursive, func)
-</pre>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="k">def</span> <span class="nf">tail_recursive</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
+ <span class="k">return</span> <span class="n">decorator_apply</span><span class="p">(</span><span class="n">TailRecursive</span><span class="p">,</span> <span class="n">func</span><span class="p">)</span>
+</pre></div>
+
+</div>
<p>Here is how you apply the upgraded decorator to the good old factorial:</p>
-<pre class="literal-block">
-&#64;tail_recursive
-def factorial(n, acc=1):
- &quot;The good old factorial&quot;
- if n == 0: return acc
- return factorial(n-1, n*acc)
-</pre>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="nd">@tail_recursive</span>
+<span class="k">def</span> <span class="nf">factorial</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">acc</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
+ <span class="s">&quot;The good old factorial&quot;</span>
+ <span class="k">if</span> <span class="n">n</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span> <span class="k">return</span> <span class="n">acc</span>
+ <span class="k">return</span> <span class="n">factorial</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">n</span><span class="o">*</span><span class="n">acc</span><span class="p">)</span>
+</pre></div>
+
+</div>
<div class="codeblock python">
<div class="highlight"><pre><span class="o">&gt;&gt;&gt;</span> <span class="k">print</span> <span class="n">factorial</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
<span class="mi">24</span>
@@ -777,17 +868,19 @@ your mind ;) Notice that there is no recursion limit now, and you can
easily compute <tt class="docutils literal">factorial(1001)</tt> 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</p>
-<pre class="literal-block">
-def fact(n): # this is not tail-recursive
- if n == 0: return 1
- return n * fact(n-1)
-</pre>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="k">def</span> <span class="nf">fact</span><span class="p">(</span><span class="n">n</span><span class="p">):</span> <span class="c"># this is not tail-recursive</span>
+ <span class="k">if</span> <span class="n">n</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span> <span class="k">return</span> <span class="mi">1</span>
+ <span class="k">return</span> <span class="n">n</span> <span class="o">*</span> <span class="n">fact</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
+</pre></div>
+
+</div>
<p>(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).</p>
</div>
<div class="section" id="caveats-and-limitations">
-<h1><a class="toc-backref" href="#id14">Caveats and limitations</a></h1>
+<h1><a class="toc-backref" href="#id15">Caveats and limitations</a></h1>
<p>The first thing you should be aware of, it the fact that decorators
have a performance penalty.
The worse case is shown by the following example:</p>
@@ -935,7 +1028,7 @@ a <em>copy</em> of the original function dictionary
</div>
</div>
<div class="section" id="compatibility-notes">
-<h1><a class="toc-backref" href="#id15">Compatibility notes</a></h1>
+<h1><a class="toc-backref" href="#id16">Compatibility notes</a></h1>
<p>Version 3.3 is the first version of the <tt class="docutils literal">decorator</tt> module to fully
support Python 3, including <a class="reference external" href="http://www.python.org/dev/peps/pep-3107/">function annotations</a>. Version 3.2 was the
first version to support Python 3 via the <tt class="docutils literal">2to3</tt> conversion tool
@@ -975,7 +1068,7 @@ tuple. That means that running the file
they are not serious.</p>
</div>
<div class="section" id="licence">
-<h1><a class="toc-backref" href="#id16">LICENCE</a></h1>
+<h1><a class="toc-backref" href="#id17">LICENCE</a></h1>
<p>Copyright (c) 2005-2012, Michele Simionato
All rights reserved.</p>
<p>Redistribution and use in source and binary forms, with or without
diff --git a/decorator/documentation.pdf b/decorator/documentation.pdf
index cf91fe1..611972e 100644
--- a/decorator/documentation.pdf
+++ b/decorator/documentation.pdf
@@ -1,5 +1,5 @@
%PDF-1.4
-%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
+%���� ReportLab Generated PDF document http://www.reportlab.com
% 'BasicFonts': class PDFDictionary
1 0 obj
% The standard fonts dictionary
@@ -7,7 +7,7 @@
/F2 3 0 R
/F3 4 0 R
/F4 7 0 R
- /F5 37 0 R
+ /F5 39 0 R
/F6 41 0 R >>
endobj
% 'F1': class PDFType1Font
@@ -56,7 +56,7 @@ endobj
6 0 obj
<< /A << /S /URI
/Type /Action
- /URI (http://pypi.python.org/pypi/decorator/3.3.2) >>
+ /URI (http://pypi.python.org/pypi/decorator/3.4.0) >>
/Border [ 0
0
0 ]
@@ -82,10 +82,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 36 0 R
+ /Dest [ 38 0 R
/XYZ
62.69291
- 311.0236
+ 293.0236
0 ]
/Rect [ 62.69291
560.7736
@@ -100,10 +100,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 36 0 R
+ /Dest [ 38 0 R
/XYZ
62.69291
- 311.0236
+ 293.0236
0 ]
/Rect [ 527.0227
560.7736
@@ -118,10 +118,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 40 0 R
+ /Dest [ 43 0 R
/XYZ
62.69291
- 699.0236
+ 675.0236
0 ]
/Rect [ 62.69291
542.7736
@@ -136,10 +136,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 40 0 R
+ /Dest [ 43 0 R
/XYZ
62.69291
- 699.0236
+ 675.0236
0 ]
/Rect [ 527.0227
542.7736
@@ -154,10 +154,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 40 0 R
+ /Dest [ 43 0 R
/XYZ
62.69291
- 462.0236
+ 438.0236
0 ]
/Rect [ 62.69291
524.7736
@@ -172,10 +172,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 40 0 R
+ /Dest [ 43 0 R
/XYZ
62.69291
- 462.0236
+ 438.0236
0 ]
/Rect [ 527.0227
524.7736
@@ -190,10 +190,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 42 0 R
+ /Dest [ 44 0 R
/XYZ
62.69291
- 451.4236
+ 427.4236
0 ]
/Rect [ 62.69291
506.7736
@@ -208,10 +208,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 42 0 R
+ /Dest [ 44 0 R
/XYZ
62.69291
- 451.4236
+ 427.4236
0 ]
/Rect [ 527.0227
506.7736
@@ -226,10 +226,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 43 0 R
+ /Dest [ 45 0 R
/XYZ
62.69291
- 459.4236
+ 435.4236
0 ]
/Rect [ 62.69291
488.7736
@@ -244,10 +244,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 43 0 R
+ /Dest [ 45 0 R
/XYZ
62.69291
- 459.4236
+ 435.4236
0 ]
/Rect [ 527.0227
488.7736
@@ -262,10 +262,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 44 0 R
+ /Dest [ 46 0 R
/XYZ
62.69291
- 463.978
+ 398.778
0 ]
/Rect [ 62.69291
470.7736
@@ -280,10 +280,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 44 0 R
+ /Dest [ 46 0 R
/XYZ
62.69291
- 463.978
+ 398.778
0 ]
/Rect [ 527.0227
470.7736
@@ -298,10 +298,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 45 0 R
+ /Dest [ 47 0 R
/XYZ
62.69291
- 729.0236
+ 647.8236
0 ]
/Rect [ 62.69291
452.7736
@@ -316,10 +316,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 45 0 R
+ /Dest [ 47 0 R
/XYZ
62.69291
- 729.0236
+ 647.8236
0 ]
/Rect [ 527.0227
452.7736
@@ -334,10 +334,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 45 0 R
+ /Dest [ 48 0 R
/XYZ
62.69291
- 195.6236
+ 765.0236
0 ]
/Rect [ 62.69291
434.7736
@@ -352,10 +352,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 45 0 R
+ /Dest [ 48 0 R
/XYZ
62.69291
- 195.6236
+ 765.0236
0 ]
/Rect [ 527.0227
434.7736
@@ -370,14 +370,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 47 0 R
+ /Dest [ 49 0 R
/XYZ
62.69291
- 366.6236
+ 267.4236
0 ]
/Rect [ 62.69291
416.7736
- 192.2729
+ 139.9329
428.7736 ]
/Subtype /Link
/Type /Annot >>
@@ -388,10 +388,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 47 0 R
+ /Dest [ 49 0 R
/XYZ
62.69291
- 366.6236
+ 267.4236
0 ]
/Rect [ 527.0227
416.7736
@@ -406,14 +406,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 49 0 R
+ /Dest [ 50 0 R
/XYZ
62.69291
- 387.8236
+ 354.6236
0 ]
/Rect [ 62.69291
398.7736
- 177.1629
+ 192.2729
410.7736 ]
/Subtype /Link
/Type /Annot >>
@@ -424,10 +424,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 49 0 R
+ /Dest [ 50 0 R
/XYZ
62.69291
- 387.8236
+ 354.6236
0 ]
/Rect [ 527.0227
398.7736
@@ -445,11 +445,11 @@ endobj
/Dest [ 51 0 R
/XYZ
62.69291
- 623.8236
+ 363.8236
0 ]
/Rect [ 62.69291
380.7736
- 228.2829
+ 177.1629
392.7736 ]
/Subtype /Link
/Type /Annot >>
@@ -463,7 +463,7 @@ endobj
/Dest [ 51 0 R
/XYZ
62.69291
- 623.8236
+ 363.8236
0 ]
/Rect [ 521.4627
380.7736
@@ -478,14 +478,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 52 0 R
+ /Dest [ 54 0 R
/XYZ
62.69291
- 239.0236
+ 599.8236
0 ]
/Rect [ 62.69291
362.7736
- 174.3929
+ 228.2829
374.7736 ]
/Subtype /Link
/Type /Annot >>
@@ -496,10 +496,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 52 0 R
+ /Dest [ 54 0 R
/XYZ
62.69291
- 239.0236
+ 599.8236
0 ]
/Rect [ 521.4627
362.7736
@@ -514,14 +514,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 62 0 R
+ /Dest [ 55 0 R
/XYZ
62.69291
- 765.0236
+ 215.0236
0 ]
/Rect [ 62.69291
344.7736
- 155.4829
+ 174.3929
356.7736 ]
/Subtype /Link
/Type /Annot >>
@@ -532,10 +532,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 62 0 R
+ /Dest [ 55 0 R
/XYZ
62.69291
- 765.0236
+ 215.0236
0 ]
/Rect [ 521.4627
344.7736
@@ -550,14 +550,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 62 0 R
+ /Dest [ 65 0 R
/XYZ
62.69291
- 414.0236
+ 765.0236
0 ]
/Rect [ 62.69291
326.7736
- 106.5829
+ 155.4829
338.7736 ]
/Subtype /Link
/Type /Annot >>
@@ -568,10 +568,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 62 0 R
+ /Dest [ 65 0 R
/XYZ
62.69291
- 414.0236
+ 765.0236
0 ]
/Rect [ 521.4627
326.7736
@@ -580,8 +580,44 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page1': class PDFPage
+% 'Annot.NUMBER31': class LinkAnnotation
36 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 65 0 R
+ /XYZ
+ 62.69291
+ 414.0236
+ 0 ]
+ /Rect [ 62.69291
+ 308.7736
+ 106.5829
+ 320.7736 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER32': class LinkAnnotation
+37 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 65 0 R
+ /XYZ
+ 62.69291
+ 414.0236
+ 0 ]
+ /Rect [ 521.4627
+ 308.7736
+ 532.5827
+ 320.7736 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page1': class PDFPage
+38 0 obj
% Page dictionary
<< /Annots [ 5 0 R
6 0 R
@@ -612,13 +648,15 @@ endobj
32 0 R
33 0 R
34 0 R
- 35 0 R ]
- /Contents 81 0 R
+ 35 0 R
+ 36 0 R
+ 37 0 R ]
+ /Contents 85 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 80 0 R
+ /Parent 84 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -630,7 +668,7 @@ endobj
/Type /Page >>
endobj
% 'F5': class PDFType1Font
-37 0 obj
+39 0 obj
% Font Helvetica-Oblique
<< /BaseFont /Helvetica-Oblique
/Encoding /WinAnsiEncoding
@@ -638,8 +676,8 @@ endobj
/Subtype /Type1
/Type /Font >>
endobj
-% 'Annot.NUMBER31': class PDFDictionary
-38 0 obj
+% 'Annot.NUMBER33': class PDFDictionary
+40 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://www.python.org/moin/PythonDecoratorLibrary) >>
@@ -647,14 +685,23 @@ endobj
0
0 ]
/Rect [ 219.6428
- 387.7736
+ 363.7736
449.1728
- 399.7736 ]
+ 375.7736 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER32': class PDFDictionary
-39 0 obj
+% 'F6': class PDFType1Font
+41 0 obj
+% Font Courier-Oblique
+<< /BaseFont /Courier-Oblique
+ /Encoding /WinAnsiEncoding
+ /Name /F6
+ /Subtype /Type1
+ /Type /Font >>
+endobj
+% 'Annot.NUMBER34': class PDFDictionary
+42 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://www.python.org/doc/2.5.2/lib/module-functools.html) >>
@@ -662,23 +709,23 @@ endobj
0
0 ]
/Rect [ 151.0486
- 154.5736
+ 130.5736
270.69
- 166.5736 ]
+ 142.5736 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Page2': class PDFPage
-40 0 obj
+43 0 obj
% Page dictionary
-<< /Annots [ 38 0 R
- 39 0 R ]
- /Contents 82 0 R
+<< /Annots [ 40 0 R
+ 42 0 R ]
+ /Contents 86 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 80 0 R
+ /Parent 84 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -689,24 +736,15 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'F6': class PDFType1Font
-41 0 obj
-% Font Courier-Oblique
-<< /BaseFont /Courier-Oblique
- /Encoding /WinAnsiEncoding
- /Name /F6
- /Subtype /Type1
- /Type /Font >>
-endobj
% 'Page3': class PDFPage
-42 0 obj
+44 0 obj
% Page dictionary
-<< /Contents 83 0 R
+<< /Contents 87 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 80 0 R
+ /Parent 84 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -718,14 +756,14 @@ endobj
/Type /Page >>
endobj
% 'Page4': class PDFPage
-43 0 obj
+45 0 obj
% Page dictionary
-<< /Contents 84 0 R
+<< /Contents 88 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 80 0 R
+ /Parent 84 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -737,14 +775,14 @@ endobj
/Type /Page >>
endobj
% 'Page5': class PDFPage
-44 0 obj
+46 0 obj
% Page dictionary
-<< /Contents 85 0 R
+<< /Contents 89 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 80 0 R
+ /Parent 84 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -756,14 +794,14 @@ endobj
/Type /Page >>
endobj
% 'Page6': class PDFPage
-45 0 obj
+47 0 obj
% Page dictionary
-<< /Contents 86 0 R
+<< /Contents 90 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 80 0 R
+ /Parent 84 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -775,14 +813,14 @@ endobj
/Type /Page >>
endobj
% 'Page7': class PDFPage
-46 0 obj
+48 0 obj
% Page dictionary
-<< /Contents 87 0 R
+<< /Contents 91 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 80 0 R
+ /Parent 84 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -794,14 +832,14 @@ endobj
/Type /Page >>
endobj
% 'Page8': class PDFPage
-47 0 obj
+49 0 obj
% Page dictionary
-<< /Contents 88 0 R
+<< /Contents 92 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 80 0 R
+ /Parent 84 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -812,31 +850,34 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER33': class PDFDictionary
-48 0 obj
-<< /A << /S /URI
- /Type /Action
- /URI (http://bugs.python.org/issue1764286) >>
- /Border [ 0
+% 'Page9': class PDFPage
+50 0 obj
+% Page dictionary
+<< /Contents 93 0 R
+ /MediaBox [ 0
0
- 0 ]
- /Rect [ 137.6966
- 95.17362
- 180.8679
- 107.1736 ]
- /Subtype /Link
- /Type /Annot >>
+ 595.2756
+ 841.8898 ]
+ /Parent 84 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
endobj
-% 'Page9': class PDFPage
-49 0 obj
+% 'Page10': class PDFPage
+51 0 obj
% Page dictionary
-<< /Annots [ 48 0 R ]
- /Contents 89 0 R
+<< /Contents 94 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 80 0 R
+ /Parent 84 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -847,8 +888,23 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER34': class PDFDictionary
-50 0 obj
+% 'Annot.NUMBER35': class PDFDictionary
+52 0 obj
+<< /A << /S /URI
+ /Type /Action
+ /URI (http://bugs.python.org/issue1764286) >>
+ /Border [ 0
+ 0
+ 0 ]
+ /Rect [ 137.6966
+ 753.7736
+ 180.8679
+ 765.7736 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER36': class PDFDictionary
+53 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496691) >>
@@ -856,22 +912,23 @@ endobj
0
0 ]
/Rect [ 62.69291
- 304.3736
+ 280.3736
363.4029
- 316.3736 ]
+ 292.3736 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page10': class PDFPage
-51 0 obj
+% 'Page11': class PDFPage
+54 0 obj
% Page dictionary
-<< /Annots [ 50 0 R ]
- /Contents 90 0 R
+<< /Annots [ 52 0 R
+ 53 0 R ]
+ /Contents 95 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 80 0 R
+ /Parent 84 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -882,15 +939,15 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Page11': class PDFPage
-52 0 obj
+% 'Page12': class PDFPage
+55 0 obj
% Page dictionary
-<< /Contents 91 0 R
+<< /Contents 96 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 80 0 R
+ /Parent 84 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -901,8 +958,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER35': class PDFDictionary
-53 0 obj
+% 'Annot.NUMBER37': class PDFDictionary
+56 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://www.python.org/dev/peps/pep-0362) >>
@@ -910,22 +967,22 @@ endobj
0
0 ]
/Rect [ 301.1597
- 140.9736
+ 116.9736
317.8397
- 152.9736 ]
+ 128.9736 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page12': class PDFPage
-54 0 obj
+% 'Page13': class PDFPage
+57 0 obj
% Page dictionary
-<< /Annots [ 53 0 R ]
- /Contents 92 0 R
+<< /Annots [ 56 0 R ]
+ /Contents 97 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 80 0 R
+ /Parent 84 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -936,15 +993,15 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Page13': class PDFPage
-55 0 obj
+% 'Page14': class PDFPage
+58 0 obj
% Page dictionary
-<< /Contents 93 0 R
+<< /Contents 98 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 80 0 R
+ /Parent 84 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -955,8 +1012,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER36': class PDFDictionary
-56 0 obj
+% 'Annot.NUMBER38': class PDFDictionary
+59 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://www.python.org/dev/peps/pep-3107/) >>
@@ -970,8 +1027,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER37': class PDFDictionary
-57 0 obj
+% 'Annot.NUMBER39': class PDFDictionary
+60 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://www.python.org/dev/peps/pep-3107/) >>
@@ -985,8 +1042,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER38': class PDFDictionary
-58 0 obj
+% 'Annot.NUMBER40': class PDFDictionary
+61 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://packages.python.org/distribute/) >>
@@ -1000,8 +1057,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER39': class PDFDictionary
-59 0 obj
+% 'Annot.NUMBER41': class PDFDictionary
+62 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://docutils.sourceforge.net/) >>
@@ -1015,8 +1072,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER40': class PDFDictionary
-60 0 obj
+% 'Annot.NUMBER42': class PDFDictionary
+63 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pygments.org/) >>
@@ -1030,8 +1087,8 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER41': class PDFDictionary
-61 0 obj
+% 'Annot.NUMBER43': class PDFDictionary
+64 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://www.phyast.pitt.edu/~micheles/python/documentation.html#class-decorators-and-decorator-factories) >>
@@ -1045,21 +1102,21 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page14': class PDFPage
-62 0 obj
+% 'Page15': class PDFPage
+65 0 obj
% Page dictionary
-<< /Annots [ 56 0 R
- 57 0 R
- 58 0 R
- 59 0 R
+<< /Annots [ 59 0 R
60 0 R
- 61 0 R ]
- /Contents 94 0 R
+ 61 0 R
+ 62 0 R
+ 63 0 R
+ 64 0 R ]
+ /Contents 99 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 80 0 R
+ /Parent 84 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1070,222 +1127,235 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'R63': class PDFCatalog
-63 0 obj
+% 'R66': class PDFCatalog
+66 0 obj
% Document Root
-<< /Outlines 65 0 R
- /PageLabels 95 0 R
+<< /Outlines 68 0 R
+ /PageLabels 100 0 R
/PageMode /UseNone
- /Pages 80 0 R
+ /Pages 84 0 R
/Type /Catalog >>
endobj
-% 'R64': class PDFInfo
-64 0 obj
+% 'R67': class PDFInfo
+67 0 obj
<< /Author (Michele Simionato)
- /CreationDate (D:20111109152256-01'00')
+ /CreationDate (D:20121018102559-01'00')
/Creator (\(unspecified\))
/Keywords ()
/Producer (ReportLab PDF Library - www.reportlab.com)
/Subject (\(unspecified\))
/Title (The decorator module) >>
endobj
-% 'R65': class PDFOutlines
-65 0 obj
-<< /Count 14
- /First 66 0 R
- /Last 79 0 R
+% 'R68': class PDFOutlines
+68 0 obj
+<< /Count 15
+ /First 69 0 R
+ /Last 83 0 R
/Type /Outlines >>
endobj
% 'Outline.0': class OutlineEntryObject
-66 0 obj
-<< /Dest [ 36 0 R
+69 0 obj
+<< /Dest [ 38 0 R
/XYZ
62.69291
- 311.0236
+ 293.0236
0 ]
- /Next 67 0 R
- /Parent 65 0 R
+ /Next 70 0 R
+ /Parent 68 0 R
/Title (Introduction) >>
endobj
% 'Outline.1': class OutlineEntryObject
-67 0 obj
-<< /Dest [ 40 0 R
+70 0 obj
+<< /Dest [ 43 0 R
/XYZ
62.69291
- 699.0236
+ 675.0236
0 ]
- /Next 68 0 R
- /Parent 65 0 R
- /Prev 66 0 R
+ /Next 71 0 R
+ /Parent 68 0 R
+ /Prev 69 0 R
/Title (Definitions) >>
endobj
% 'Outline.2': class OutlineEntryObject
-68 0 obj
-<< /Dest [ 40 0 R
+71 0 obj
+<< /Dest [ 43 0 R
/XYZ
62.69291
- 462.0236
+ 438.0236
0 ]
- /Next 69 0 R
- /Parent 65 0 R
- /Prev 67 0 R
+ /Next 72 0 R
+ /Parent 68 0 R
+ /Prev 70 0 R
/Title (Statement of the problem) >>
endobj
% 'Outline.3': class OutlineEntryObject
-69 0 obj
-<< /Dest [ 42 0 R
+72 0 obj
+<< /Dest [ 44 0 R
/XYZ
62.69291
- 451.4236
+ 427.4236
0 ]
- /Next 70 0 R
- /Parent 65 0 R
- /Prev 68 0 R
+ /Next 73 0 R
+ /Parent 68 0 R
+ /Prev 71 0 R
/Title (The solution) >>
endobj
% 'Outline.4': class OutlineEntryObject
-70 0 obj
-<< /Dest [ 43 0 R
+73 0 obj
+<< /Dest [ 45 0 R
/XYZ
62.69291
- 459.4236
+ 435.4236
0 ]
- /Next 71 0 R
- /Parent 65 0 R
- /Prev 69 0 R
+ /Next 74 0 R
+ /Parent 68 0 R
+ /Prev 72 0 R
/Title (A trace decorator) >>
endobj
% 'Outline.5': class OutlineEntryObject
-71 0 obj
-<< /Dest [ 44 0 R
+74 0 obj
+<< /Dest [ 46 0 R
/XYZ
62.69291
- 463.978
+ 398.778
0 ]
- /Next 72 0 R
- /Parent 65 0 R
- /Prev 70 0 R
+ /Next 75 0 R
+ /Parent 68 0 R
+ /Prev 73 0 R
/Title (decorator is a decorator) >>
endobj
% 'Outline.6': class OutlineEntryObject
-72 0 obj
-<< /Dest [ 45 0 R
+75 0 obj
+<< /Dest [ 47 0 R
/XYZ
62.69291
- 729.0236
+ 647.8236
0 ]
- /Next 73 0 R
- /Parent 65 0 R
- /Prev 71 0 R
+ /Next 76 0 R
+ /Parent 68 0 R
+ /Prev 74 0 R
/Title (blocking) >>
endobj
% 'Outline.7': class OutlineEntryObject
-73 0 obj
-<< /Dest [ 45 0 R
+76 0 obj
+<< /Dest [ 48 0 R
/XYZ
62.69291
- 195.6236
+ 765.0236
0 ]
- /Next 74 0 R
- /Parent 65 0 R
- /Prev 72 0 R
+ /Next 77 0 R
+ /Parent 68 0 R
+ /Prev 75 0 R
/Title (async) >>
endobj
% 'Outline.8': class OutlineEntryObject
-74 0 obj
-<< /Dest [ 47 0 R
+77 0 obj
+<< /Dest [ 49 0 R
/XYZ
62.69291
- 366.6236
+ 267.4236
0 ]
- /Next 75 0 R
- /Parent 65 0 R
- /Prev 73 0 R
- /Title (The FunctionMaker class) >>
+ /Next 78 0 R
+ /Parent 68 0 R
+ /Prev 76 0 R
+ /Title (contextmanager) >>
endobj
% 'Outline.9': class OutlineEntryObject
-75 0 obj
-<< /Dest [ 49 0 R
+78 0 obj
+<< /Dest [ 50 0 R
/XYZ
62.69291
- 387.8236
+ 354.6236
0 ]
- /Next 76 0 R
- /Parent 65 0 R
- /Prev 74 0 R
- /Title (Getting the source code) >>
+ /Next 79 0 R
+ /Parent 68 0 R
+ /Prev 77 0 R
+ /Title (The FunctionMaker class) >>
endobj
% 'Outline.10': class OutlineEntryObject
-76 0 obj
+79 0 obj
<< /Dest [ 51 0 R
/XYZ
62.69291
- 623.8236
+ 363.8236
0 ]
- /Next 77 0 R
- /Parent 65 0 R
- /Prev 75 0 R
- /Title (Dealing with third party decorators) >>
+ /Next 80 0 R
+ /Parent 68 0 R
+ /Prev 78 0 R
+ /Title (Getting the source code) >>
endobj
% 'Outline.11': class OutlineEntryObject
-77 0 obj
-<< /Dest [ 52 0 R
+80 0 obj
+<< /Dest [ 54 0 R
/XYZ
62.69291
- 239.0236
+ 599.8236
0 ]
- /Next 78 0 R
- /Parent 65 0 R
- /Prev 76 0 R
- /Title (Caveats and limitations) >>
+ /Next 81 0 R
+ /Parent 68 0 R
+ /Prev 79 0 R
+ /Title (Dealing with third party decorators) >>
endobj
% 'Outline.12': class OutlineEntryObject
-78 0 obj
-<< /Dest [ 62 0 R
+81 0 obj
+<< /Dest [ 55 0 R
+ /XYZ
+ 62.69291
+ 215.0236
+ 0 ]
+ /Next 82 0 R
+ /Parent 68 0 R
+ /Prev 80 0 R
+ /Title (Caveats and limitations) >>
+endobj
+% 'Outline.13': class OutlineEntryObject
+82 0 obj
+<< /Dest [ 65 0 R
/XYZ
62.69291
765.0236
0 ]
- /Next 79 0 R
- /Parent 65 0 R
- /Prev 77 0 R
+ /Next 83 0 R
+ /Parent 68 0 R
+ /Prev 81 0 R
/Title (Compatibility notes) >>
endobj
-% 'Outline.13': class OutlineEntryObject
-79 0 obj
-<< /Dest [ 62 0 R
+% 'Outline.14': class OutlineEntryObject
+83 0 obj
+<< /Dest [ 65 0 R
/XYZ
62.69291
414.0236
0 ]
- /Parent 65 0 R
- /Prev 78 0 R
+ /Parent 68 0 R
+ /Prev 82 0 R
/Title (LICENCE) >>
endobj
-% 'R80': class PDFPages
-80 0 obj
+% 'R84': class PDFPages
+84 0 obj
% page tree
-<< /Count 14
- /Kids [ 36 0 R
- 40 0 R
- 42 0 R
+<< /Count 15
+ /Kids [ 38 0 R
43 0 R
44 0 R
45 0 R
46 0 R
47 0 R
+ 48 0 R
49 0 R
+ 50 0 R
51 0 R
- 52 0 R
54 0 R
55 0 R
- 62 0 R ]
+ 57 0 R
+ 58 0 R
+ 65 0 R ]
/Type /Pages >>
endobj
-% 'R81': class PDFStream
-81 0 obj
+% 'R85': class PDFStream
+85 0 obj
% page stream
-<< /Length 9160 >>
+<< /Length 9046 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -1350,7 +1420,7 @@ 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 (3.3.2 \(2011-11-09\)) Tj T* ET
+BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (3.4.0 \(2012-10-18\)) Tj T* ET
Q
Q
q
@@ -1393,7 +1463,7 @@ q
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/3.3.2) Tj T* ET
+BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (http://pypi.python.org/pypi/decorator/3.4.0) Tj T* ET
Q
Q
q
@@ -1413,8 +1483,7 @@ Q
q
1 0 0 1 91.03937 3 cm
q
-0 0 0 rg
-BT 1 0 0 1 0 2 Tm /F4 10 Tf 12 TL (easy_install decorator) Tj T* ET
+BT 1 0 0 1 0 2 Tm 12 TL /F4 10 Tf 0 0 0 rg (easy_install) Tj ( ) Tj (decorator) Tj T* ET
Q
Q
q
@@ -1448,17 +1517,17 @@ 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 323.0236 cm
+1 0 0 1 62.69291 305.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
-1 0 0 1 0 237 cm
+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 (Introduction) Tj T* ET
Q
Q
q
-1 0 0 1 397.8898 237 cm
+1 0 0 1 397.8898 255 cm
q
0 0 .501961 rg
0 0 .501961 RG
@@ -1466,12 +1535,26 @@ BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (1) Tj T* -66.44 0 Td ET
Q
Q
q
-1 0 0 1 0 219 cm
+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 (Definitions) 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 (2) 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 (Statement of the problem) Tj T* ET
+Q
+Q
+q
1 0 0 1 397.8898 219 cm
q
0 0 .501961 rg
@@ -1482,7 +1565,7 @@ 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 (Statement of the problem) Tj T* ET
+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
@@ -1490,13 +1573,13 @@ q
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
+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 183 cm
q
-BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (The solution) Tj T* ET
+BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (A ) Tj /F3 10 Tf (trace ) Tj /F2 10 Tf (decorator) Tj T* ET
Q
Q
q
@@ -1504,13 +1587,13 @@ q
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
+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 165 cm
q
-BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (A ) Tj /F3 10 Tf (trace ) Tj /F2 10 Tf (decorator) Tj T* ET
+BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 .501961 rg (decorator ) Tj /F2 10 Tf (is a decorator) Tj T* ET
Q
Q
q
@@ -1518,13 +1601,13 @@ q
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
+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 147 cm
q
-BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 .501961 rg (decorator ) Tj /F2 10 Tf (is a decorator) Tj T* ET
+BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 .501961 rg (blocking) Tj T* ET
Q
Q
q
@@ -1532,13 +1615,13 @@ q
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
+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 129 cm
q
-BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 .501961 rg (blocking) Tj T* ET
+BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 .501961 rg (async) Tj T* ET
Q
Q
q
@@ -1546,13 +1629,13 @@ q
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
+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 111 cm
q
-BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 .501961 rg (async) Tj T* ET
+BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (contextmanager) Tj T* ET
Q
Q
q
@@ -1560,7 +1643,7 @@ q
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
+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
@@ -1574,7 +1657,7 @@ q
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
+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
@@ -1588,7 +1671,7 @@ q
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
+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
@@ -1602,7 +1685,7 @@ q
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
+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
@@ -1616,7 +1699,7 @@ q
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
+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
@@ -1630,7 +1713,7 @@ q
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 (14) Tj T* -60.88 0 Td ET
+BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 60.88 0 Td (15) Tj T* -60.88 0 Td ET
Q
Q
q
@@ -1644,33 +1727,33 @@ q
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 (14) Tj T* -60.88 0 Td ET
+BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 60.88 0 Td (15) Tj T* -60.88 0 Td ET
Q
Q
q
Q
Q
q
-1 0 0 1 62.69291 290.0236 cm
+1 0 0 1 62.69291 272.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 224.0236 cm
+1 0 0 1 62.69291 206.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 218.0236 cm
+1 0 0 1 62.69291 200.0236 cm
Q
q
-1 0 0 1 62.69291 218.0236 cm
+1 0 0 1 62.69291 200.0236 cm
Q
q
-1 0 0 1 62.69291 206.0236 cm
+1 0 0 1 62.69291 188.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -1691,10 +1774,10 @@ q
Q
Q
q
-1 0 0 1 62.69291 200.0236 cm
+1 0 0 1 62.69291 182.0236 cm
Q
q
-1 0 0 1 62.69291 188.0236 cm
+1 0 0 1 62.69291 170.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -1715,10 +1798,10 @@ q
Q
Q
q
-1 0 0 1 62.69291 182.0236 cm
+1 0 0 1 62.69291 164.0236 cm
Q
q
-1 0 0 1 62.69291 170.0236 cm
+1 0 0 1 62.69291 152.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -1739,10 +1822,10 @@ q
Q
Q
q
-1 0 0 1 62.69291 164.0236 cm
+1 0 0 1 62.69291 146.0236 cm
Q
q
-1 0 0 1 62.69291 152.0236 cm
+1 0 0 1 62.69291 134.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -1763,63 +1846,57 @@ q
Q
Q
q
-1 0 0 1 62.69291 152.0236 cm
+1 0 0 1 62.69291 134.0236 cm
Q
q
-1 0 0 1 62.69291 110.0236 cm
+1 0 0 1 62.69291 92.02362 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 80.02362 cm
-q
-BT 1 0 0 1 0 14 Tm 1.093735 Tw 12 TL /F1 10 Tf 0 0 0 rg (The aim of the ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (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 ET
-Q
-Q
endstream
endobj
-% 'R82': class PDFStream
-82 0 obj
+% 'R86': class PDFStream
+86 0 obj
% page stream
-<< /Length 6156 >>
+<< /Length 7546 >>
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
+1 0 0 1 62.69291 717.0236 cm
q
-BT 1 0 0 1 0 14 Tm 2.234987 Tw 12 TL /F1 10 Tf 0 0 0 rg (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
+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 /F4 10 Tf (decorator ) Tj /F1 10 Tf (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
q
-1 0 0 1 62.69291 711.0236 cm
+1 0 0 1 62.69291 687.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 /F4 10 Tf (documentation.py ) Tj /F1 10 Tf (file, which) Tj T* 0 Tw (contains this documentation in the form of doctests.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 678.0236 cm
+1 0 0 1 62.69291 654.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 636.0236 cm
+1 0 0 1 62.69291 612.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 630.0236 cm
+1 0 0 1 62.69291 606.0236 cm
Q
q
-1 0 0 1 62.69291 630.0236 cm
+1 0 0 1 62.69291 606.0236 cm
Q
q
-1 0 0 1 62.69291 606.0236 cm
+1 0 0 1 62.69291 582.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -1839,10 +1916,10 @@ q
Q
Q
q
-1 0 0 1 62.69291 600.0236 cm
+1 0 0 1 62.69291 576.0236 cm
Q
q
-1 0 0 1 62.69291 576.0236 cm
+1 0 0 1 62.69291 552.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -1862,42 +1939,42 @@ q
Q
Q
q
-1 0 0 1 62.69291 576.0236 cm
+1 0 0 1 62.69291 552.0236 cm
Q
q
-1 0 0 1 62.69291 534.0236 cm
+1 0 0 1 62.69291 510.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 /F4 10 Tf (staticmethod ) Tj /F1 10 Tf (and) Tj T* 0 Tw 1.506651 Tw /F4 10 Tf (classmethod ) Tj /F1 10 Tf (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 504.0236 cm
+1 0 0 1 62.69291 480.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 474.0236 cm
+1 0 0 1 62.69291 450.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 441.0236 cm
+1 0 0 1 62.69291 417.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 363.0236 cm
+1 0 0 1 62.69291 339.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 /F4 10 Tf (memoize ) Tj /F1 10 Tf (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 /F4 10 Tf (memoize ) Tj /F1 10 Tf (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 2.683984 Tw (preserve the signature. A simple implementation could be the following \(notice that in general it is) Tj T* 0 Tw (impossible to memoize correctly something that depends on non-hashable arguments\):) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 173.8236 cm
+1 0 0 1 62.69291 149.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -1910,49 +1987,42 @@ q
n -6 -6 468.6898 180 re B*
Q
q
-0 0 0 rg
-BT 1 0 0 1 0 158 Tm /F4 10 Tf 12 TL (def memoize_uw\(func\):) Tj T* ( func.cache = {}) Tj T* ( def memoize\(*args, **kw\):) Tj T* ( if kw: # frozenset is used to ensure hashability) Tj T* ( key = args, frozenset\(kw.iteritems\(\)\)) Tj T* ( else:) Tj T* ( key = args) Tj T* ( cache = func.cache) Tj T* ( if key in cache:) Tj T* ( return cache[key]) Tj T* ( else:) Tj T* ( cache[key] = result = func\(*args, **kw\)) Tj T* ( return result) Tj T* ( return functools.update_wrapper\(memoize, func\)) Tj T* ET
+BT 1 0 0 1 0 158 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (memoize_uw) Tj 0 0 0 rg (\() Tj (func) Tj (\):) Tj T* ( ) Tj (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (cache) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj ({}) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 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 (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (if) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (kw) Tj (:) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# frozenset is used to ensure hashability) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj (key) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (args) Tj (,) Tj ( ) Tj 0 .501961 0 rg (frozenset) Tj 0 0 0 rg (\() Tj (kw) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (iteritems) Tj (\(\)\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (else) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj (key) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (args) Tj T* ( ) Tj (cache) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (cache) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (if) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (key) Tj ( ) Tj /F3 10 Tf .666667 .133333 1 rg (in) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (cache) Tj (:) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (cache) Tj ([) Tj (key) Tj (]) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (else) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj (cache) Tj ([) Tj (key) Tj (]) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (result) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (func) Tj (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (result) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (functools) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (update_wrapper) Tj (\() Tj (memoize) Tj (,) Tj ( ) Tj (func) Tj (\)) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 117.8236 cm
+1 0 0 1 62.69291 93.82362 cm
q
BT 1 0 0 1 0 38 Tm 1.801412 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here we 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 /F4 10 Tf (__name__) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (__doc__) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (__module__ ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (__dict__ ) Tj /F1 10 Tf (from the original function to the decorated function) Tj T* 0 Tw (by hand\).) Tj T* ET
Q
Q
-q
-1 0 0 1 62.69291 87.82362 cm
-q
-BT 1 0 0 1 0 14 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 /F5 10 Tf (not ) Tj /F1 10 Tf (define a signature-preserving decorator, since in) Tj T* 0 Tw ET
-Q
-Q
endstream
endobj
-% 'R83': class PDFStream
-83 0 obj
+% 'R87': class PDFStream
+87 0 obj
% page stream
-<< /Length 6791 >>
+<< /Length 8057 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 753.0236 cm
+1 0 0 1 62.69291 729.0236 cm
q
-BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (general ) Tj /F4 10 Tf (memoize_uw ) Tj /F1 10 Tf (returns a function with a ) Tj /F5 10 Tf (different signature ) Tj /F1 10 Tf (from the original function.) Tj T* ET
+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 /F5 10 Tf (not ) Tj /F1 10 Tf (define a signature-preserving decorator, since in) Tj T* 0 Tw (general ) Tj /F4 10 Tf (memoize_uw ) Tj /F1 10 Tf (returns a function with a ) Tj /F5 10 Tf (different signature ) Tj /F1 10 Tf (from the original function.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 735.0236 cm
+1 0 0 1 62.69291 711.0236 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 665.8236 cm
+1 0 0 1 62.69291 641.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -1972,13 +2042,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 633.8236 cm
+1 0 0 1 62.69291 609.8236 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 /F4 10 Tf (x) Tj /F1 10 Tf (, 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 576.6236 cm
+1 0 0 1 62.69291 552.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -1998,13 +2068,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 532.6236 cm
+1 0 0 1 62.69291 508.6236 cm
q
BT 1 0 0 1 0 26 Tm .411235 Tw 12 TL /F1 10 Tf 0 0 0 rg (This means that introspection tools such as pydoc will give wrong informations about the signature of ) Tj /F4 10 Tf (f1) Tj /F1 10 Tf (.) Tj T* 0 Tw .161654 Tw (This is pretty bad: pydoc will tell you that the function accepts a generic signature ) Tj /F4 10 Tf (*args) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (**kw) Tj /F1 10 Tf (, but when) Tj T* 0 Tw (you try to call the function with more than an argument, you will get an error:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 463.4236 cm
+1 0 0 1 62.69291 439.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -2024,19 +2094,19 @@ Q
Q
Q
q
-1 0 0 1 62.69291 430.4236 cm
+1 0 0 1 62.69291 406.4236 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 388.4236 cm
+1 0 0 1 62.69291 364.4236 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.362976 Tw (signature-preserving decorators from the application programmer. The ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (function in the) Tj T* 0 Tw /F4 10 Tf (decorator ) Tj /F1 10 Tf (module is such a factory:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 355.2236 cm
+1 0 0 1 62.69291 331.2236 cm
q
q
1 0 0 1 0 0 cm
@@ -2056,13 +2126,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 299.2236 cm
+1 0 0 1 62.69291 275.2236 cm
q
-BT 1 0 0 1 0 38 Tm 1.716412 Tw 12 TL /F4 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf (takes two arguments, a caller function describing the functionality of the decorator and a) Tj T* 0 Tw .821984 Tw (function to be decorated; it returns the decorated function. The caller function must have signature ) Tj /F4 10 Tf (\(f,) Tj T* 0 Tw .65061 Tw (*args, **kw\) ) Tj /F1 10 Tf (and it must call the original function ) Tj /F4 10 Tf (f ) Tj /F1 10 Tf (with arguments ) Tj /F4 10 Tf (args ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (kw) Tj /F1 10 Tf (, implementing the) Tj T* 0 Tw (wanted capability, i.e. memoization in this case:) Tj T* ET
+BT 1 0 0 1 0 38 Tm 1.716412 Tw 12 TL /F4 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf (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 /F4 10 Tf (\(f,) Tj ( ) Tj (*args,) Tj ( ) Tj (**kw\) ) Tj /F1 10 Tf (and it must call the original function ) Tj /F4 10 Tf (f ) Tj /F1 10 Tf (with arguments ) Tj /F4 10 Tf (args ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (kw) Tj /F1 10 Tf (, 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 146.0236 cm
+1 0 0 1 62.69291 122.0236 cm
q
q
1 0 0 1 0 0 cm
@@ -2075,52 +2145,30 @@ q
n -6 -6 468.6898 144 re B*
Q
q
-0 0 0 rg
-BT 1 0 0 1 0 122 Tm /F4 10 Tf 12 TL (def _memoize\(func, *args, **kw\):) Tj T* ( if kw: # frozenset is used to ensure hashability) Tj T* ( key = args, frozenset\(kw.iteritems\(\)\)) Tj T* ( else:) Tj T* ( key = args) Tj T* ( cache = func.cache # attributed added by memoize) Tj T* ( if key in cache:) Tj T* ( return cache[key]) Tj T* ( else:) Tj T* ( cache[key] = result = func\(*args, **kw\)) Tj T* ( return result) Tj T* ET
+BT 1 0 0 1 0 122 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (_memoize) Tj 0 0 0 rg (\() Tj (func) Tj (,) Tj ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (if) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (kw) Tj (:) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# frozenset is used to ensure hashability) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj (key) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (args) Tj (,) Tj ( ) Tj 0 .501961 0 rg (frozenset) Tj 0 0 0 rg (\() Tj (kw) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (iteritems) Tj (\(\)\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (else) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj (key) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (args) Tj T* ( ) Tj (cache) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (cache) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# attributed added by memoize) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (if) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (key) Tj ( ) Tj /F3 10 Tf .666667 .133333 1 rg (in) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (cache) Tj (:) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (cache) Tj ([) Tj (key) Tj (]) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (else) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj (cache) Tj ([) Tj (key) Tj (]) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (result) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (func) Tj (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (result) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 126.0236 cm
+1 0 0 1 62.69291 102.0236 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 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 36 re B*
-Q
-q
-0 0 0 rg
-BT 1 0 0 1 0 14 Tm /F4 10 Tf 12 TL (def memoize\(f\):) Tj T* ( f.cache = {}) Tj T* ET
-Q
-Q
-Q
-Q
-Q
endstream
endobj
-% 'R84': class PDFStream
-84 0 obj
+% 'R88': class PDFStream
+88 0 obj
% page stream
-<< /Length 6759 >>
+<< /Length 7115 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 739.8236 cm
+1 0 0 1 62.69291 715.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -2130,31 +2178,30 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 24 re B*
+n -6 -6 468.6898 48 re B*
Q
q
-0 0 0 rg
-BT 1 0 0 1 0 2 Tm /F4 10 Tf 12 TL ( return decorator\(_memoize, f\)) Tj T* ET
+BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (memoize) Tj 0 0 0 rg (\() Tj (f) Tj (\):) Tj T* ( ) Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (cache) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj ({}) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (decorator) Tj (\() Tj (_memoize) Tj (,) Tj ( ) Tj (f) Tj (\)) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 695.8236 cm
+1 0 0 1 62.69291 671.8236 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 /F4 10 Tf (memoize_uw ) Tj /F1 10 Tf (approach, which is based on nested functions, is that the) Tj T* 0 Tw 2.59528 Tw (decorator module forces you to lift the inner function at the outer level \() Tj /F5 10 Tf (flat is better than nested) Tj /F1 10 Tf (\).) Tj T* 0 Tw (Moreover, you are forced to pass explicitly the function you want to decorate to the caller function.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 677.8236 cm
+1 0 0 1 62.69291 653.8236 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 536.6236 cm
+1 0 0 1 62.69291 512.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -2174,13 +2221,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 516.6236 cm
+1 0 0 1 62.69291 492.6236 cm
q
BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (The signature of ) Tj /F4 10 Tf (heavy_computation ) Tj /F1 10 Tf (is the one you would expect:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 471.4236 cm
+1 0 0 1 62.69291 447.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -2200,19 +2247,19 @@ Q
Q
Q
q
-1 0 0 1 62.69291 438.4236 cm
+1 0 0 1 62.69291 414.4236 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 (trace ) Tj /F2 17.5 Tf (decorator) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 408.4236 cm
+1 0 0 1 62.69291 384.4236 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 /F4 10 Tf (trace ) Tj /F1 10 Tf (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 351.2236 cm
+1 0 0 1 62.69291 327.2236 cm
q
q
1 0 0 1 0 0 cm
@@ -2225,15 +2272,14 @@ q
n -6 -6 468.6898 48 re B*
Q
q
-0 0 0 rg
-BT 1 0 0 1 0 26 Tm /F4 10 Tf 12 TL (def _trace\(f, *args, **kw\):) Tj T* ( print "calling %s with args %s, %s" % \(f.__name__, args, kw\)) Tj T* ( return f\(*args, **kw\)) Tj T* ET
+BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (_trace) Tj 0 0 0 rg (\() Tj (f) Tj (,) Tj ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (print) Tj /F4 10 Tf 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ("calling ) Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg ( with args ) Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg (, ) Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg (") Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (%) Tj 0 0 0 rg ( ) Tj (\() Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__name__) Tj (,) Tj ( ) Tj (args) Tj (,) Tj ( ) Tj (kw) Tj (\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (f) Tj (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\)) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 306.0236 cm
+1 0 0 1 62.69291 282.0236 cm
q
q
1 0 0 1 0 0 cm
@@ -2246,22 +2292,21 @@ q
n -6 -6 468.6898 36 re B*
Q
q
-0 0 0 rg
-BT 1 0 0 1 0 14 Tm /F4 10 Tf 12 TL (def trace\(f\):) Tj T* ( return decorator\(_trace, f\)) Tj T* ET
+BT 1 0 0 1 0 14 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (trace) Tj 0 0 0 rg (\() Tj (f) Tj (\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (decorator) Tj (\() Tj (_trace) Tj (,) Tj ( ) Tj (f) Tj (\)) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 286.0236 cm
+1 0 0 1 62.69291 262.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 228.8236 cm
+1 0 0 1 62.69291 204.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -2281,13 +2326,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 208.8236 cm
+1 0 0 1 62.69291 184.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 /F4 10 Tf (f1 ) Tj /F1 10 Tf (works) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 163.6236 cm
+1 0 0 1 62.69291 139.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -2307,14 +2352,23 @@ Q
Q
Q
q
-1 0 0 1 62.69291 143.6236 cm
+1 0 0 1 62.69291 119.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
+
+endstream
+endobj
+% 'R89': class PDFStream
+89 0 obj
+% page stream
+<< /Length 8852 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 98.42362 cm
+1 0 0 1 62.69291 727.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -2334,23 +2388,14 @@ Q
Q
Q
q
-1 0 0 1 62.69291 78.42362 cm
+1 0 0 1 62.69291 707.8236 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
-
-endstream
-endobj
-% 'R85': class PDFStream
-85 0 obj
-% page stream
-<< /Length 8633 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 645.178 cm
+1 0 0 1 62.69291 579.978 cm
q
q
.988825 0 0 .988825 0 0 cm
@@ -2370,14 +2415,14 @@ Q
Q
Q
q
-1 0 0 1 62.69291 625.178 cm
+1 0 0 1 62.69291 559.978 cm
q
0 0 0 rg
BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (That includes even functions with exotic signatures like the following:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 507.978 cm
+1 0 0 1 62.69291 442.778 cm
q
q
1 0 0 1 0 0 cm
@@ -2397,26 +2442,26 @@ Q
Q
Q
q
-1 0 0 1 62.69291 475.978 cm
+1 0 0 1 62.69291 410.778 cm
q
0 0 0 rg
BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .84561 Tw (Notice that the support for exotic signatures has been deprecated in Python 2.6 and removed in Python) Tj T* 0 Tw (3.0.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 442.978 cm
+1 0 0 1 62.69291 377.778 cm
q
BT 1 0 0 1 0 3.5 Tm 21 TL /F3 17.5 Tf 0 0 0 rg (decorator ) Tj /F2 17.5 Tf (is a decorator) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 340.978 cm
+1 0 0 1 62.69291 275.778 cm
q
-BT 1 0 0 1 0 86 Tm .643876 Tw 12 TL /F1 10 Tf 0 0 0 rg (It may be annoying to write a caller function \(like the ) Tj /F4 10 Tf (_trace ) Tj /F1 10 Tf (function above\) and then a trivial wrapper) Tj T* 0 Tw 1.803615 Tw (\() Tj /F4 10 Tf (def trace\(f\): return decorator\(_trace, f\)) Tj /F1 10 Tf (\) every time. For this reason, the ) Tj /F4 10 Tf (decorator) Tj T* 0 Tw .334269 Tw /F1 10 Tf (module provides an easy shortcut to convert the caller function into a signature-preserving decorator: you) Tj T* 0 Tw 3.443735 Tw (can just call ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (with a single argument. In our example you can just write ) Tj /F4 10 Tf (trace =) Tj T* 0 Tw 1.056342 Tw (decorator\(_trace\)) Tj /F1 10 Tf (. The ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (function can also be used as a signature-changing decorator,) Tj T* 0 Tw 3.177752 Tw (just as ) Tj /F4 10 Tf (classmethod ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (staticmethod) Tj /F1 10 Tf (. However, ) Tj /F4 10 Tf (classmethod ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (staticmethod ) Tj /F1 10 Tf (return) Tj T* 0 Tw 1.693615 Tw (generic objects which are not callable, while ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (returns signature-preserving decorators, i.e.) Tj T* 0 Tw (functions of a single argument. For instance, you can write directly) Tj T* ET
+BT 1 0 0 1 0 86 Tm .643876 Tw 12 TL /F1 10 Tf 0 0 0 rg (It may be annoying to write a caller function \(like the ) Tj /F4 10 Tf (_trace ) Tj /F1 10 Tf (function above\) and then a trivial wrapper) Tj T* 0 Tw 1.510888 Tw (\() Tj /F4 10 Tf (def) Tj ( ) Tj (trace\(f\):) Tj ( ) Tj (return) Tj ( ) Tj (decorator\(_trace,) Tj ( ) Tj (f\)) Tj /F1 10 Tf (\) every time. For this reason, the ) Tj /F4 10 Tf (decorator) Tj T* 0 Tw .334269 Tw /F1 10 Tf (module provides an easy shortcut to convert the caller function into a signature-preserving decorator: you) Tj T* 0 Tw 7.364269 Tw (can just call ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (with a single argument. In our example you can just write) Tj T* 0 Tw .951647 Tw /F4 10 Tf (trace) Tj ( ) Tj (=) Tj ( ) Tj (decorator\(_trace\)) Tj /F1 10 Tf (. The ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (function can also be used as a signature-changing) Tj T* 0 Tw 1.077752 Tw (decorator, just as ) Tj /F4 10 Tf (classmethod ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (staticmethod) Tj /F1 10 Tf (. However, ) Tj /F4 10 Tf (classmethod ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (staticmethod) Tj T* 0 Tw .531797 Tw /F1 10 Tf (return generic objects which are not callable, while ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (returns signature-preserving decorators,) Tj T* 0 Tw (i.e. functions of a single argument. For instance, you can write directly) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 271.778 cm
+1 0 0 1 62.69291 206.578 cm
q
q
1 0 0 1 0 0 cm
@@ -2436,13 +2481,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 239.778 cm
+1 0 0 1 62.69291 174.578 cm
q
BT 1 0 0 1 0 14 Tm 1.806654 Tw 12 TL /F1 10 Tf 0 0 0 rg (and now ) Tj /F4 10 Tf (trace ) Tj /F1 10 Tf (will be a decorator. Actually ) Tj /F4 10 Tf (trace ) Tj /F1 10 Tf (is a ) Tj /F4 10 Tf (partial ) Tj /F1 10 Tf (object which can be used as a) Tj T* 0 Tw (decorator:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 194.578 cm
+1 0 0 1 62.69291 129.378 cm
q
q
1 0 0 1 0 0 cm
@@ -2462,14 +2507,23 @@ Q
Q
Q
q
-1 0 0 1 62.69291 174.578 cm
+1 0 0 1 62.69291 109.378 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
+% 'R90': class PDFStream
+90 0 obj
+% page stream
+<< /Length 7156 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 93.378 cm
+1 0 0 1 62.69291 691.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -2488,35 +2542,26 @@ Q
Q
Q
Q
-
-endstream
-endobj
-% 'R86': class PDFStream
-86 0 obj
-% page stream
-<< /Length 5826 >>
-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
+1 0 0 1 62.69291 659.8236 cm
q
BT 1 0 0 1 0 14 Tm 2.44686 Tw 12 TL /F1 10 Tf 0 0 0 rg (If you are using an old Python version \(Python 2.4\) the ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (module provides a poor man) Tj T* 0 Tw (replacement for ) Tj /F4 10 Tf (functools.partial) Tj /F1 10 Tf (.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 708.0236 cm
+1 0 0 1 62.69291 626.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 666.0236 cm
+1 0 0 1 62.69291 584.8236 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 /F4 10 Tf (stdin) Tj /F1 10 Tf (, 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
q
-1 0 0 1 62.69291 488.8236 cm
+1 0 0 1 62.69291 407.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -2529,21 +2574,20 @@ q
n -6 -6 468.6898 168 re B*
Q
q
-0 0 0 rg
-BT 1 0 0 1 0 146 Tm /F4 10 Tf 12 TL (def blocking\(not_avail\):) Tj T* ( def blocking\(f, *args, **kw\):) Tj T* ( if not hasattr\(f, "thread"\): # no thread running) Tj T* ( def set_result\(\): f.result = f\(*args, **kw\)) Tj T* ( f.thread = threading.Thread\(None, set_result\)) Tj T* ( f.thread.start\(\)) Tj T* ( return not_avail) Tj T* ( elif f.thread.isAlive\(\):) Tj T* ( return not_avail) Tj T* ( else: # the thread is ended, return the stored result) Tj T* ( del f.thread) Tj T* ( return f.result) Tj T* ( return decorator\(blocking\)) Tj T* ET
+BT 1 0 0 1 0 146 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (blocking) Tj 0 0 0 rg (\() Tj (not_avail) Tj (\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (blocking) Tj 0 0 0 rg (\() Tj (f) Tj (,) Tj ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (if) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf .666667 .133333 1 rg (not) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (hasattr) Tj 0 0 0 rg (\() Tj (f) Tj (,) Tj ( ) Tj .729412 .129412 .129412 rg ("thread") Tj 0 0 0 rg (\):) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# no thread running) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (set_result) Tj 0 0 0 rg (\(\):) Tj ( ) Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (result) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (f) Tj (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\)) Tj T* ( ) Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (thread) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (threading) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Thread) Tj (\() Tj 0 .501961 0 rg (None) Tj 0 0 0 rg (,) Tj ( ) Tj (set_result) Tj (\)) Tj T* ( ) Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (thread) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (start) Tj (\(\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (not_avail) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (elif) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (thread) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (isAlive) Tj (\(\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (not_avail) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (else) Tj /F4 10 Tf 0 0 0 rg (:) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# the thread is ended, return the stored result) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (del) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (thread) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (result) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (decorator) Tj (\() Tj (blocking) Tj (\)) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 456.8236 cm
+1 0 0 1 62.69291 375.6236 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 /F4 10 Tf (blocking ) Tj /F1 10 Tf (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 207.6236 cm
+1 0 0 1 62.69291 126.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -2562,41 +2606,56 @@ Q
Q
Q
Q
+
+endstream
+endobj
+% 'R91': class PDFStream
+91 0 obj
+% page stream
+<< /Length 7381 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 174.6236 cm
+1 0 0 1 62.69291 744.0236 cm
q
BT 1 0 0 1 0 3.5 Tm 21 TL /F3 17.5 Tf 0 0 0 rg (async) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 108.6236 cm
+1 0 0 1 62.69291 702.0236 cm
q
-BT 1 0 0 1 0 50 Tm 1.647485 Tw 12 TL /F1 10 Tf 0 0 0 rg (We have just seen an examples of a simple decorator factory, implemented as a function returning a) Tj T* 0 Tw .29784 Tw (decorator. For more complex situations, it is more convenient to implement decorator factories as classes) Tj T* 0 Tw .657674 Tw (returning callable objects that can be used as signature-preserving decorators. The suggested pattern to) Tj T* 0 Tw 2.109398 Tw (do that is to introduce a helper method ) Tj /F4 10 Tf (call\(self, func, *args, **kw\) ) Tj /F1 10 Tf (and to call it in the) Tj T* 0 Tw /F4 10 Tf (__call__\(self, func\) ) Tj /F1 10 Tf (method.) Tj T* ET
+0 0 0 rg
+BT 1 0 0 1 0 26 Tm /F1 10 Tf 12 TL 1.647485 Tw (We have just seen an examples of a simple decorator factory, implemented as a function returning a) Tj T* 0 Tw .29784 Tw (decorator. For more complex situations, it is more convenient to implement decorator factories as classes) Tj T* 0 Tw (returning callable objects that can be converted into decorators.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 78.62362 cm
+1 0 0 1 62.69291 636.0236 cm
q
-BT 1 0 0 1 0 14 Tm .166654 Tw 12 TL /F1 10 Tf 0 0 0 rg (As an example, here I show a decorator which is able to convert a blocking function into an asynchronous ) Tj T* 0 Tw .437633 Tw (function. The function, when called, is executed in a separate thread. Moreover, it is possible to set three) Tj T* 0 Tw ET
+BT 1 0 0 1 0 50 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 2.477126 Tw (asynchronous function. The function, when called, is executed in a separate thread. Moreover, it is) Tj T* 0 Tw .288443 Tw (possible to set three callbacks ) Tj /F4 10 Tf (on_success) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (on_failure ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (on_closing) Tj /F1 10 Tf (, to specify how to manage) Tj T* 0 Tw 1.854724 Tw (the function call \(of course the code here is just an example, it is not a recommended way of doing) Tj T* 0 Tw (multi-threaded programming\). The implementation is the following:) Tj T* ET
Q
Q
-
-endstream
-endobj
-% 'R87': class PDFStream
-87 0 obj
-% page stream
-<< /Length 3574 >>
-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
+1 0 0 1 62.69291 578.8236 cm
+q
+q
+1 0 0 1 0 0 cm
+q
+1 0 0 1 6.6 6.6 cm
q
-BT 1 0 0 1 0 14 Tm .074597 Tw 12 TL /F1 10 Tf 0 0 0 rg (callbacks ) Tj /F4 10 Tf (on_success) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (on_failure ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (on_closing) Tj /F1 10 Tf (, to specify how to manage the function call. The) Tj T* 0 Tw (implementation is the following:) Tj T* ET
+.662745 .662745 .662745 RG
+.5 w
+.960784 .960784 .862745 rg
+n -6 -6 468.6898 48 re B*
+Q
+q
+BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (on_success) Tj 0 0 0 rg (\() Tj (result) Tj (\):) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# default implementation) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj .729412 .129412 .129412 rg ("Called on the result of the function") Tj 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (result) Tj T* ET
+Q
+Q
+Q
Q
Q
q
-1 0 0 1 62.69291 683.8236 cm
+1 0 0 1 62.69291 521.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -2609,15 +2668,14 @@ q
n -6 -6 468.6898 48 re B*
Q
q
-0 0 0 rg
-BT 1 0 0 1 0 26 Tm /F4 10 Tf 12 TL (def on_success\(result\): # default implementation) Tj T* ( "Called on the result of the function") Tj T* ( return result) Tj T* ET
+BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (on_failure) Tj 0 0 0 rg (\() Tj (exc_info) Tj (\):) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# default implementation) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj .729412 .129412 .129412 rg ("Called if the function fails") Tj 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (pass) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 626.6236 cm
+1 0 0 1 62.69291 464.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -2630,15 +2688,14 @@ q
n -6 -6 468.6898 48 re B*
Q
q
-0 0 0 rg
-BT 1 0 0 1 0 26 Tm /F4 10 Tf 12 TL (def on_failure\(exc_info\): # default implementation) Tj T* ( "Called if the function fails") Tj T* ( pass) Tj T* ET
+BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (on_closing) Tj 0 0 0 rg (\(\):) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# default implementation) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj .729412 .129412 .129412 rg ("Called at the end, both in case of success and failure") Tj 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (pass) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 569.4236 cm
+1 0 0 1 62.69291 83.22362 cm
q
q
1 0 0 1 0 0 cm
@@ -2648,18 +2705,26 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 48 re B*
+n -6 -6 468.6898 372 re B*
Q
q
-0 0 0 rg
-BT 1 0 0 1 0 26 Tm /F4 10 Tf 12 TL (def on_closing\(\): # default implementation) Tj T* ( "Called at the end, both in case of success and failure") Tj T* ( pass) Tj T* ET
+BT 1 0 0 1 0 350 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (class) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf 0 0 1 rg (Async) Tj /F4 10 Tf 0 0 0 rg (\() Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\):) Tj T* ( ) Tj /F6 10 Tf .729412 .129412 .129412 rg (""") Tj T* ( A decorator converting blocking functions into asynchronous) Tj T* ( functions, by using threads or processes. Examples:) Tj T* T* ( async_with_threads = Async\(threading.Thread\)) Tj T* ( async_with_processes = Async\(multiprocessing.Process\)) Tj T* ( """) Tj /F4 10 Tf 0 0 0 rg T* T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 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 ( ) Tj (threadfactory) Tj (,) Tj ( ) Tj (on_success) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (on_success) Tj (,) Tj T* ( ) Tj (on_failure) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (on_failure) Tj (,) Tj ( ) Tj (on_closing) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (on_closing) Tj (\):) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (threadfactory) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (threadfactory) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (on_success) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (on_success) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (on_failure) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (on_failure) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (on_closing) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (on_closing) Tj T* T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 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 ( ) Tj (func) Tj (,) Tj ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (try) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj (counter) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (counter) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (except) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf .823529 .254902 .227451 rg (AttributeError) Tj /F4 10 Tf 0 0 0 rg (:) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# instantiate the counter at the first call) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj (counter) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (counter) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (itertools) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (count) Tj (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (\)) Tj T* ( ) Tj (name) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg (') Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg (-) Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg (') Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (%) Tj 0 0 0 rg ( ) Tj (\() Tj (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__name__) Tj (,) Tj ( ) Tj (counter) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (next) Tj (\(\)\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (func_wrapper) Tj 0 0 0 rg (\(\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (try) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj (result) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (func) Tj (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (except) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (on_failure) Tj (\() Tj (sys) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (exc_info) Tj (\(\)\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (else) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (on_success) Tj (\() Tj (result) Tj (\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (finally) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ET
Q
Q
Q
Q
Q
+
+endstream
+endobj
+% 'R92': class PDFStream
+92 0 obj
+% page stream
+<< /Length 7221 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 128.2236 cm
+1 0 0 1 62.69291 703.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -2669,40 +2734,30 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 432 re B*
+n -6 -6 468.6898 60 re B*
Q
q
-0 0 0 rg
-BT 1 0 0 1 0 410 Tm /F4 10 Tf 12 TL (class Async\(object\):) Tj T* ( """) Tj T* ( A decorator converting blocking functions into asynchronous) Tj T* ( functions, by using threads or processes. Examples:) Tj T* T* ( async_with_threads = Async\(threading.Thread\)) Tj T* ( async_with_processes = Async\(multiprocessing.Process\)) Tj T* ( """) Tj T* T* ( def __init__\(self, threadfactory\):) Tj T* ( self.threadfactory = threadfactory) Tj T* T* ( def __call__\(self, func, on_success=on_success,) Tj T* ( on_failure=on_failure, on_closing=on_closing\):) Tj T* ( # every decorated function has its own independent thread counter) Tj T* ( func.counter = itertools.count\(1\)) Tj T* ( func.on_success = on_success) Tj T* ( func.on_failure = on_failure) Tj T* ( func.on_closing = on_closing) Tj T* ( return decorator\(self.call, func\)) Tj T* T* ( def call\(self, func, *args, **kw\):) Tj T* ( def func_wrapper\(\):) Tj T* ( try:) Tj T* ( result = func\(*args, **kw\)) Tj T* ( except:) Tj T* ( func.on_failure\(sys.exc_info\(\)\)) Tj T* ( else:) Tj T* ( return func.on_success\(result\)) Tj T* ( finally:) Tj T* ( func.on_closing\(\)) Tj T* ( name = '%s-%s' % \(func.__name__, func.counter.next\(\)\)) Tj T* ( thread = self.threadfactory\(None, func_wrapper, name\)) Tj T* ( thread.start\(\)) Tj T* ( return thread) Tj T* ET
+BT 1 0 0 1 0 38 Tm 12 TL /F4 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (on_closing) Tj (\(\)) Tj T* ( ) Tj (thread) Tj ( ) 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 (threadfactory) Tj (\() Tj 0 .501961 0 rg (None) Tj 0 0 0 rg (,) Tj ( ) Tj (func_wrapper) Tj (,) Tj ( ) Tj (name) Tj (\)) Tj T* ( ) Tj (thread) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (start) Tj (\(\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (thread) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 96.22362 cm
+1 0 0 1 62.69291 671.8236 cm
q
BT 1 0 0 1 0 14 Tm .865984 Tw 12 TL /F1 10 Tf 0 0 0 rg (The decorated function returns the current execution thread, which can be stored and checked later, for) Tj T* 0 Tw (instance to verify that the thread ) Tj /F4 10 Tf (.isAlive\(\)) Tj /F1 10 Tf (.) Tj T* ET
Q
Q
-
-endstream
-endobj
-% 'R88': class PDFStream
-88 0 obj
-% page stream
-<< /Length 7588 >>
-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
+1 0 0 1 62.69291 629.8236 cm
q
0 0 0 rg
BT 1 0 0 1 0 26 Tm /F1 10 Tf 12 TL .691654 Tw (Here is an example of usage. Suppose one wants to write some data to an external resource which can) Tj T* 0 Tw .21683 Tw (be accessed by a single user at once \(for instance a printer\). Then the access to the writing function must) Tj T* 0 Tw (be locked. Here is a minimalistic example:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 575.8236 cm
+1 0 0 1 62.69291 476.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -2715,20 +2770,20 @@ q
n -6 -6 468.6898 144 re B*
Q
q
-BT 1 0 0 1 0 122 Tm 12 TL /F4 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (async) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (Async) Tj (\() Tj (threading) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Thread) Tj (\)) Tj T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (datalist) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj ([]) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# for simplicity the written data are stored into a list.) Tj /F4 10 Tf 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj .666667 .133333 1 rg (@async) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (write) Tj 0 0 0 rg (\() Tj (data) Tj (\):) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# append data to the datalist by locking) Tj /F4 10 Tf 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (with) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (threading) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Lock) Tj (\(\):) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj (time) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (sleep) Tj (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (\)) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# emulate some long running operation) Tj /F4 10 Tf 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj (datalist) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (append) Tj (\() Tj (data) Tj (\)) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# other operations not requiring a lock here) Tj T* ET
+BT 1 0 0 1 0 122 Tm 12 TL /F4 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (async) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (decorator) Tj (\() Tj (Async) Tj (\() Tj (threading) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Thread) Tj (\)\)) Tj T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (datalist) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj ([]) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# for simplicity the written data are stored into a list.) Tj /F4 10 Tf 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj .666667 .133333 1 rg (@async) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (write) Tj 0 0 0 rg (\() Tj (data) Tj (\):) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# append data to the datalist by locking) Tj /F4 10 Tf 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (with) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (threading) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Lock) Tj (\(\):) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj (time) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (sleep) Tj (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (\)) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# emulate some long running operation) Tj /F4 10 Tf 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj (datalist) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (append) Tj (\() Tj (data) Tj (\)) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# other operations not requiring a lock here) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 543.8236 cm
+1 0 0 1 62.69291 444.6236 cm
q
BT 1 0 0 1 0 14 Tm .905868 Tw 12 TL /F1 10 Tf 0 0 0 rg (Each call to ) Tj /F4 10 Tf (write ) Tj /F1 10 Tf (will create a new writer thread, but there will be no synchronization problems since) Tj T* 0 Tw /F4 10 Tf (write ) Tj /F1 10 Tf (is locked.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 378.6236 cm
+1 0 0 1 62.69291 279.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -2748,25 +2803,124 @@ Q
Q
Q
q
-1 0 0 1 62.69291 345.6236 cm
+1 0 0 1 62.69291 246.4236 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 216.4236 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 /F4 10 Tf (contextmanager ) Tj /F1 10 Tf (decorator, able to convert) Tj T* 0 Tw (generator functions into ) Tj /F4 10 Tf (GeneratorContextManager ) Tj /F1 10 Tf (factories. For instance if you write) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 123.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 84 re B*
+Q
+q
+BT 1 0 0 1 0 62 Tm 12 TL /F4 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (from) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf 0 0 1 rg (contextlib) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (import) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (contextmanager) Tj 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 /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (before_after) Tj 0 0 0 rg (\() Tj (before) Tj (,) Tj ( ) Tj (after) Tj (\):) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (print) Tj /F4 10 Tf 0 0 0 rg (\() Tj (before) Tj (\)) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (yield) Tj /F4 10 Tf 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (print) Tj /F4 10 Tf 0 0 0 rg (\() Tj (after) Tj (\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 91.22362 cm
+q
+BT 1 0 0 1 0 14 Tm .150888 Tw 12 TL /F1 10 Tf 0 0 0 rg (then ) Tj /F4 10 Tf (before_after ) Tj /F1 10 Tf (is a factory function returning ) Tj /F4 10 Tf (GeneratorContextManager ) Tj /F1 10 Tf (objects which can be) Tj T* 0 Tw (used with the ) Tj /F4 10 Tf (with ) Tj /F1 10 Tf (statement:) Tj T* ET
+Q
+Q
+
+endstream
+endobj
+% 'R93': class PDFStream
+93 0 obj
+% page stream
+<< /Length 7180 >>
+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
+BT 1 0 0 1 0 86 Tm 12 TL /F4 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (ba) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (before_after) Tj (\() Tj .729412 .129412 .129412 rg ('BEFORE') Tj 0 0 0 rg (,) Tj ( ) Tj .729412 .129412 .129412 rg ('AFTER') Tj 0 0 0 rg (\)) Tj T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (type) Tj 0 0 0 rg (\() Tj (ba) Tj (\)) Tj T* .4 .4 .4 rg (<) Tj /F3 10 Tf 0 .501961 0 rg (class) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (') Tj /F3 10 Tf 0 0 1 rg (contextlib) Tj /F4 10 Tf .4 .4 .4 rg (.) Tj 0 0 0 rg (GeneratorContextManager) Tj .729412 .129412 .129412 rg (') Tj (>) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (with) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (ba) Tj (:) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (print) Tj /F4 10 Tf 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('hello') Tj 0 0 0 rg T* (BEFORE) Tj T* (hello) Tj T* (AFTER) 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 26 Tm .462488 Tw 12 TL /F1 10 Tf 0 0 0 rg (Basically, it is as if the content of the ) Tj /F4 10 Tf (with ) Tj /F1 10 Tf (block was executed in the place of the ) Tj /F4 10 Tf (yield ) Tj /F1 10 Tf (expression in) Tj T* 0 Tw 2.691797 Tw (the generator function. In Python 3.2 ) Tj /F4 10 Tf (GeneratorContextManager ) Tj /F1 10 Tf (objects were enhanced with a) Tj T* 0 Tw /F4 10 Tf (__call__ ) Tj /F1 10 Tf (method, so that they can be used as decorators as in this example:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 494.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
+BT 1 0 0 1 0 86 Tm 12 TL /F4 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 /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (hello) Tj 0 0 0 rg (\(\):) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (print) Tj /F4 10 Tf 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg ('hello') 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 (hello) Tj (\(\)) Tj T* (BEFORE) Tj T* (hello) Tj T* (AFTER) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 366.6236 cm
+q
+BT 1 0 0 1 0 110 Tm .20561 Tw 12 TL /F1 10 Tf 0 0 0 rg (The ) Tj /F4 10 Tf (ba ) Tj /F1 10 Tf (decorator is basically inserting a ) Tj /F4 10 Tf (with) Tj ( ) Tj (ba: ) Tj /F1 10 Tf (block inside the function. However there two issues:) Tj T* 0 Tw 1.402126 Tw (the first is that ) Tj /F4 10 Tf (GeneratorContextManager ) Tj /F1 10 Tf (objects are callable only in Python 3.2, so the previous) Tj T* 0 Tw .356905 Tw (example will break in older versions of Python; the second is that ) Tj /F4 10 Tf (GeneratorContextManager ) Tj /F1 10 Tf (objects) Tj T* 0 Tw .57561 Tw (do not preserve the signature of the decorated functions: the decorated ) Tj /F4 10 Tf (hello ) Tj /F1 10 Tf (function here will have a) Tj T* 0 Tw 3.990814 Tw (generic signature ) Tj /F4 10 Tf (hello\(*args,) Tj ( ) Tj (**kwargs\) ) Tj /F1 10 Tf (but will break when called with more than zero) Tj T* 0 Tw 7.708314 Tw (arguments. For such reasons the decorator module, starting with release 3.4, offers a) Tj T* 0 Tw .616647 Tw /F4 10 Tf (decorator.contextmanager ) Tj /F1 10 Tf (decorator that solves both problems and works even in Python 2.5. The) Tj T* 0 Tw .34998 Tw (usage is the same and factories decorated with ) Tj /F4 10 Tf (decorator.contextmanager ) Tj /F1 10 Tf (will returns instances of) Tj T* 0 Tw 4.152823 Tw /F4 10 Tf (ContextManager) Tj /F1 10 Tf (, a subclass of ) Tj /F4 10 Tf (contextlib.GeneratorContextManager ) Tj /F1 10 Tf (with a ) Tj /F4 10 Tf (__call__) Tj T* 0 Tw /F1 10 Tf (method acting as a signature-preserving decorator.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 333.6236 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 (FunctionMaker ) Tj /F2 17.5 Tf (class) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 279.6236 cm
+1 0 0 1 62.69291 267.6236 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 /F4 10 Tf (decorator ) Tj /F1 10 Tf (module is implemented. The basic) Tj T* 0 Tw 1.545868 Tw (building block is a ) Tj /F4 10 Tf (FunctionMaker ) Tj /F1 10 Tf (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 /F4 10 Tf (FunctionMaker ) Tj /F1 10 Tf (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 /F4 10 Tf (decorator_apply) Tj /F1 10 Tf (\).) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 237.6236 cm
+1 0 0 1 62.69291 225.6236 cm
q
BT 1 0 0 1 0 26 Tm .414597 Tw 12 TL /F4 10 Tf 0 0 0 rg (FunctionMaker ) Tj /F1 10 Tf (provides a ) Tj /F4 10 Tf (.create ) Tj /F1 10 Tf (classmethod which takes as input the name, signature, and body) Tj T* 0 Tw .632927 Tw (of the function we want to generate as well as the execution environment were the function is generated) Tj T* 0 Tw (by ) Tj /F4 10 Tf (exec) Tj /F1 10 Tf (. Here is an example:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 144.4236 cm
+1 0 0 1 62.69291 132.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -2786,40 +2940,34 @@ Q
Q
Q
q
-1 0 0 1 62.69291 112.4236 cm
+1 0 0 1 62.69291 100.4236 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 /F4 10 Tf (% ) Tj /F1 10 Tf (sign!) Tj T* ET
Q
Q
-q
-1 0 0 1 62.69291 82.42362 cm
-q
-BT 1 0 0 1 0 14 Tm 1.995433 Tw 12 TL /F4 10 Tf 0 0 0 rg (FunctionMaker.create ) Tj /F1 10 Tf (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 ET
-Q
-Q
endstream
endobj
-% 'R89': class PDFStream
-89 0 obj
+% 'R94': class PDFStream
+94 0 obj
% page stream
-<< /Length 7391 >>
+<< /Length 7802 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 753.0236 cm
+1 0 0 1 62.69291 729.0236 cm
q
-BT 1 0 0 1 0 2 Tm 12 TL /F4 10 Tf 0 0 0 rg (__doc__) Tj /F1 10 Tf (.) Tj T* ET
+BT 1 0 0 1 0 26 Tm 1.995433 Tw 12 TL /F4 10 Tf 0 0 0 rg (FunctionMaker.create ) Tj /F1 10 Tf (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 /F4 10 Tf (__doc__) Tj /F1 10 Tf (.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 711.0236 cm
+1 0 0 1 62.69291 687.0236 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 /F4 10 Tf (addsource=True ) Tj /F1 10 Tf (and a ) Tj /F4 10 Tf (__source__ ) Tj /F1 10 Tf (attribute will be added to the) Tj T* 0 Tw (generated function:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 617.8236 cm
+1 0 0 1 62.69291 593.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -2839,31 +2987,31 @@ Q
Q
Q
q
-1 0 0 1 62.69291 477.8236 cm
+1 0 0 1 62.69291 453.8236 cm
q
BT 1 0 0 1 0 122 Tm .870651 Tw 12 TL /F4 10 Tf 0 0 0 rg (FunctionMaker.create ) Tj /F1 10 Tf (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 /F4 10 Tf (FunctionMaker.create ) Tj /F1 10 Tf (instead of ) Tj /F4 10 Tf (decorator) Tj /F1 10 Tf (, 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 /F4 10 Tf (__init__ ) Tj /F1 10 Tf (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 /F4 10 Tf (FunctionMaker.create) Tj T* 0 Tw 3.405814 Tw /F1 10 Tf (is a function, a ) Tj /F4 10 Tf (FunctionMaker ) Tj /F1 10 Tf (object is instantiated internally, with attributes ) Tj /F4 10 Tf (args) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (varargs) Tj /F1 10 Tf (,) Tj T* 0 Tw 5.509982 Tw /F4 10 Tf (keywords ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (defaults ) Tj /F1 10 Tf (which are the the return values of the standard library function) Tj T* 0 Tw .561318 Tw /F4 10 Tf (inspect.getargspec) Tj /F1 10 Tf (. For each argument in the ) Tj /F4 10 Tf (args ) Tj /F1 10 Tf (\(which is a list of strings containing the names) Tj T* 0 Tw 1.599985 Tw (of the mandatory arguments\) an attribute ) Tj /F4 10 Tf (arg0) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (arg1) Tj /F1 10 Tf (, ..., ) Tj /F4 10 Tf (argN ) Tj /F1 10 Tf (is also generated. Finally, there is a) Tj T* 0 Tw /F4 10 Tf (signature ) Tj /F1 10 Tf (attribute, a string with the signature of the original function.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 399.8236 cm
+1 0 0 1 62.69291 375.8236 cm
q
BT 1 0 0 1 0 62 Tm 4.63311 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice that while I do not have plans to change or remove the functionality provided in the) Tj T* 0 Tw 1.00936 Tw /F4 10 Tf (FunctionMaker ) Tj /F1 10 Tf (class, I do not guarantee that it will stay unchanged forever. For instance, right now I) Tj T* 0 Tw .791318 Tw (am using the traditional string interpolation syntax for function templates, but Python 2.6 and Python 3.0) Tj T* 0 Tw .712093 Tw (provide a newer interpolation syntax and I may use the new syntax in the future. On the other hand, the) Tj T* 0 Tw .639985 Tw (functionality provided by ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (has been there from version 0.1 and it is guaranteed to stay there) Tj T* 0 Tw (forever.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 366.8236 cm
+1 0 0 1 62.69291 342.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 288.8236 cm
+1 0 0 1 62.69291 264.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 /F4 10 Tf (FunctionMaker.create ) Tj /F1 10 Tf (uses ) Tj /F4 10 Tf (exec ) Tj /F1 10 Tf (to generate the decorated function. Therefore) Tj T* 0 Tw 2.542126 Tw /F4 10 Tf (inspect.getsource ) Tj /F1 10 Tf (will not work for decorated functions. That means that the usual '??' trick in) Tj T* 0 Tw 2.163059 Tw (IPython will give you the \(right on the spot\) message ) Tj /F4 10 Tf (Dynamically generated function. No) Tj T* 0 Tw .563314 Tw (source code available) Tj /F1 10 Tf (. In the past I have considered this acceptable, since ) Tj /F4 10 Tf (inspect.getsource) Tj T* 0 Tw 1.790697 Tw /F1 10 Tf (does not really work even with regular decorators. In that case ) Tj /F4 10 Tf (inspect.getsource ) Tj /F1 10 Tf (gives you the) Tj T* 0 Tw (wrapper source code which is probably not what you want:) Tj T* ET
+BT 1 0 0 1 0 62 Tm 5.045529 Tw 12 TL /F1 10 Tf 0 0 0 rg (Internally ) Tj /F4 10 Tf (FunctionMaker.create ) Tj /F1 10 Tf (uses ) Tj /F4 10 Tf (exec ) Tj /F1 10 Tf (to generate the decorated function. Therefore) Tj T* 0 Tw 2.542126 Tw /F4 10 Tf (inspect.getsource ) Tj /F1 10 Tf (will not work for decorated functions. That means that the usual '??' 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 /F4 10 Tf (Dynamically) Tj ( ) Tj (generated) Tj ( ) Tj (function.) Tj ( ) Tj (No) Tj ( ) Tj (source) Tj ( ) Tj (code available) Tj /F1 10 Tf (. In the past I have considered) Tj T* 0 Tw .945366 Tw (this acceptable, since ) Tj /F4 10 Tf (inspect.getsource ) Tj /F1 10 Tf (does not really work even with regular decorators. In that) Tj T* 0 Tw (case ) Tj /F4 10 Tf (inspect.getsource ) Tj /F1 10 Tf (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 219.6236 cm
+1 0 0 1 62.69291 195.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -2876,15 +3024,14 @@ q
n -6 -6 468.6898 60 re B*
Q
q
-0 0 0 rg
-BT 1 0 0 1 0 38 Tm /F4 10 Tf 12 TL (def identity_dec\(func\):) Tj T* ( def wrapper\(*args, **kw\):) Tj T* ( return func\(*args, **kw\)) Tj T* ( return wrapper) Tj T* ET
+BT 1 0 0 1 0 38 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (identity_dec) Tj 0 0 0 rg (\() Tj (func) Tj (\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 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 (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (func) Tj (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (wrapper) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 114.4236 cm
+1 0 0 1 62.69291 90.42362 cm
q
q
1 0 0 1 0 0 cm
@@ -2903,29 +3050,23 @@ Q
Q
Q
Q
-q
-1 0 0 1 62.69291 82.42362 cm
-q
-BT 1 0 0 1 0 14 Tm 1.471235 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, ) Tj T* 0 Tw 1.541235 Tw (even in Python 2.7 and 3.1. There is however a workaround. The decorator module adds an attribute) Tj T* 0 Tw ET
-Q
-Q
endstream
endobj
-% 'R90': class PDFStream
-90 0 obj
+% 'R95': class PDFStream
+95 0 obj
% page stream
-<< /Length 5339 >>
+<< /Length 7279 >>
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
+1 0 0 1 62.69291 717.0236 cm
q
-BT 1 0 0 1 0 14 Tm .103984 Tw 12 TL /F4 10 Tf 0 0 0 rg (.__wrapped__ ) Tj /F1 10 Tf (to the decorated function, containing a reference to the original function. The easy way to) Tj T* 0 Tw (get the source code is to call ) Tj /F4 10 Tf (inspect.getsource ) Tj /F1 10 Tf (on the undecorated function:) Tj T* ET
+BT 1 0 0 1 0 38 Tm 1.471235 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,) Tj T* 0 Tw 1.541235 Tw (even in Python 2.7 and 3.1. There is however a workaround. The decorator module adds an attribute) Tj T* 0 Tw .103984 Tw /F4 10 Tf (.__wrapped__ ) Tj /F1 10 Tf (to the decorated function, containing a reference to the original function. The easy way to) Tj T* 0 Tw (get the source code is to call ) Tj /F4 10 Tf (inspect.getsource ) Tj /F1 10 Tf (on the undecorated function:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 635.8236 cm
+1 0 0 1 62.69291 611.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -2945,19 +3086,19 @@ Q
Q
Q
q
-1 0 0 1 62.69291 602.8236 cm
+1 0 0 1 62.69291 578.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 548.8236 cm
+1 0 0 1 62.69291 524.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 /F4 10 Tf (decorator) Tj /F1 10 Tf (. You can use a ) Tj /F4 10 Tf (FunctionMaker ) Tj /F1 10 Tf (to implement that functionality as follows:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 431.6236 cm
+1 0 0 1 62.69291 407.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -2970,27 +3111,26 @@ q
n -6 -6 468.6898 108 re B*
Q
q
-0 0 0 rg
-BT 1 0 0 1 0 86 Tm /F4 10 Tf 12 TL (def decorator_apply\(dec, func\):) Tj T* ( """) Tj T* ( Decorate a function by preserving the signature even if dec) Tj T* ( is not a signature-preserving decorator.) Tj T* ( """) Tj T* ( return FunctionMaker.create\() Tj T* ( func, 'return decorated\(%\(signature\)s\)',) Tj T* ( dict\(decorated=dec\(func\)\), __wrapped__=func\)) Tj T* ET
+BT 1 0 0 1 0 86 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (decorator_apply) Tj 0 0 0 rg (\() Tj (dec) Tj (,) Tj ( ) Tj (func) Tj (\):) Tj 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 /F4 10 Tf 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (FunctionMaker) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (create) Tj (\() Tj T* ( ) Tj (func) Tj (,) Tj ( ) Tj .729412 .129412 .129412 rg ('return decorated\() Tj /F3 10 Tf .733333 .4 .533333 rg (%\(signature\)s) Tj /F4 10 Tf .729412 .129412 .129412 rg (\)') Tj 0 0 0 rg (,) Tj T* ( ) Tj 0 .501961 0 rg (dict) Tj 0 0 0 rg (\() Tj (decorated) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (dec) Tj (\() Tj (func) Tj (\)\),) Tj ( ) Tj (__wrapped__) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (func) Tj (\)) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 399.6236 cm
+1 0 0 1 62.69291 375.6236 cm
q
BT 1 0 0 1 0 14 Tm .698314 Tw 12 TL /F4 10 Tf 0 0 0 rg (decorator_apply ) Tj /F1 10 Tf (sets the attribute ) Tj /F4 10 Tf (.__wrapped__ ) Tj /F1 10 Tf (of the generated function to the original function,) Tj T* 0 Tw (so that you can get the right source code.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 357.6236 cm
+1 0 0 1 62.69291 333.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 /F4 10 Tf (decorator ) Tj /F1 10 Tf (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 /F4 10 Tf (decorator_apply ) Tj /F1 10 Tf (to your toolbox and use it if you need to.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 303.6236 cm
+1 0 0 1 62.69291 279.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 /F4 10 Tf (decorator_apply) Tj /F1 10 Tf (, 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
@@ -3006,11 +3146,10 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 216 re B*
+n -6 -6 468.6898 192 re B*
Q
q
-0 0 0 rg
-BT 1 0 0 1 0 194 Tm /F4 10 Tf 12 TL (class TailRecursive\(object\):) Tj T* ( """) 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 T* T* ( def __init__\(self, func\):) Tj T* ( self.func = func) Tj T* ( self.firstcall = True) Tj T* ( self.CONTINUE = object\(\) # sentinel) Tj T* T* ( def __call__\(self, *args, **kwd\):) Tj T* ( CONTINUE = self.CONTINUE) Tj T* ( if self.firstcall:) Tj T* ( func = self.func) Tj T* ( self.firstcall = False) Tj T* ET
+BT 1 0 0 1 0 170 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (class) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf 0 0 1 rg (TailRecursive) Tj /F4 10 Tf 0 0 0 rg (\() Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\):) Tj 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 /F4 10 Tf 0 0 0 rg T* T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 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 ( ) Tj (func) Tj (\):) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (func) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (func) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (firstcall) Tj ( ) 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 ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\(\)) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# sentinel) Tj /F4 10 Tf 0 0 0 rg T* T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 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 ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kwd) Tj (\):) Tj T* ( ) Tj (CONTINUE) Tj ( ) 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 T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (if) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (firstcall) Tj (:) Tj T* ET
Q
Q
Q
@@ -3019,14 +3158,14 @@ Q
endstream
endobj
-% 'R91': class PDFStream
-91 0 obj
+% 'R96': class PDFStream
+96 0 obj
% page stream
-<< /Length 4367 >>
+<< /Length 7146 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 607.8236 cm
+1 0 0 1 62.69291 583.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -3036,25 +3175,24 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 156 re B*
+n -6 -6 468.6898 180 re B*
Q
q
-0 0 0 rg
-BT 1 0 0 1 0 134 Tm /F4 10 Tf 12 TL ( try:) Tj T* ( while True:) Tj T* ( result = func\(*args, **kwd\)) Tj T* ( if result is CONTINUE: # update arguments) Tj T* ( args, kwd = self.argskwd) Tj T* ( else: # last call) Tj T* ( return result) Tj T* ( finally:) Tj T* ( self.firstcall = True) Tj T* ( else: # return the arguments of the tail call) Tj T* ( self.argskwd = args, kwd) Tj T* ( return CONTINUE) Tj T* ET
+BT 1 0 0 1 0 158 Tm 12 TL /F4 10 Tf 0 0 0 rg ( ) Tj (func) Tj ( ) 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 T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (firstcall) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (False) Tj 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (try) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (while) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (True) Tj 0 0 0 rg (:) Tj T* ( ) Tj (result) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (func) Tj (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kwd) Tj (\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (if) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (result) Tj ( ) Tj /F3 10 Tf .666667 .133333 1 rg (is) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (CONTINUE) Tj (:) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# update arguments) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj (args) Tj (,) Tj ( ) Tj (kwd) Tj ( ) 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 T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (else) Tj /F4 10 Tf 0 0 0 rg (:) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# last call) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (result) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (finally) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (firstcall) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (True) Tj 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (else) Tj /F4 10 Tf 0 0 0 rg (:) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# return the arguments of the tail call) Tj /F4 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 ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (args) Tj (,) Tj ( ) Tj (kwd) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (CONTINUE) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 587.8236 cm
+1 0 0 1 62.69291 563.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 542.6236 cm
+1 0 0 1 62.69291 518.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -3067,22 +3205,21 @@ q
n -6 -6 468.6898 36 re B*
Q
q
-0 0 0 rg
-BT 1 0 0 1 0 14 Tm /F4 10 Tf 12 TL (def tail_recursive\(func\):) Tj T* ( return decorator_apply\(TailRecursive, func\)) Tj T* ET
+BT 1 0 0 1 0 14 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (tail_recursive) Tj 0 0 0 rg (\() Tj (func) Tj (\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (decorator_apply) Tj (\() Tj (TailRecursive) Tj (,) Tj ( ) Tj (func) Tj (\)) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 522.6236 cm
+1 0 0 1 62.69291 498.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 441.4236 cm
+1 0 0 1 62.69291 417.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -3095,15 +3232,14 @@ q
n -6 -6 468.6898 72 re B*
Q
q
-0 0 0 rg
-BT 1 0 0 1 0 50 Tm /F4 10 Tf 12 TL (@tail_recursive) Tj T* (def factorial\(n, acc=1\):) Tj T* ( "The good old factorial") Tj T* ( if n == 0: return acc) Tj T* ( return factorial\(n-1, n*acc\)) Tj T* ET
+BT 1 0 0 1 0 50 Tm 12 TL /F4 10 Tf .666667 .133333 1 rg (@tail_recursive) Tj 0 0 0 rg T* /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (factorial) Tj 0 0 0 rg (\() Tj (n) Tj (,) Tj ( ) Tj (acc) Tj .4 .4 .4 rg (=) Tj (1) Tj 0 0 0 rg (\):) Tj T* ( ) Tj .729412 .129412 .129412 rg ("The good old factorial") Tj 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (if) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (n) Tj ( ) Tj .4 .4 .4 rg (==) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (0) Tj 0 0 0 rg (:) Tj ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (acc) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (factorial) Tj (\() Tj (n) Tj .4 .4 .4 rg (-) Tj (1) Tj 0 0 0 rg (,) Tj ( ) Tj (n) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (acc) Tj (\)) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 396.2236 cm
+1 0 0 1 62.69291 372.2236 cm
q
q
1 0 0 1 0 0 cm
@@ -3123,13 +3259,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 340.2236 cm
+1 0 0 1 62.69291 316.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 /F4 10 Tf (factorial\(1001\) ) Tj /F1 10 Tf (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 283.0236 cm
+1 0 0 1 62.69291 259.0236 cm
q
q
1 0 0 1 0 0 cm
@@ -3142,28 +3278,27 @@ q
n -6 -6 468.6898 48 re B*
Q
q
-0 0 0 rg
-BT 1 0 0 1 0 26 Tm /F4 10 Tf 12 TL (def fact\(n\): # this is not tail-recursive) Tj T* ( if n == 0: return 1) Tj T* ( return n * fact\(n-1\)) Tj T* ET
+BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (fact) Tj 0 0 0 rg (\() Tj (n) Tj (\):) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# this is not tail-recursive) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (if) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (n) Tj ( ) Tj .4 .4 .4 rg (==) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (0) Tj 0 0 0 rg (:) Tj ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj .4 .4 .4 rg (1) Tj 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (n) Tj ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg ( ) Tj (fact) Tj (\() Tj (n) Tj .4 .4 .4 rg (-) Tj (1) Tj 0 0 0 rg (\)) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 251.0236 cm
+1 0 0 1 62.69291 227.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 218.0236 cm
+1 0 0 1 62.69291 194.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 188.0236 cm
+1 0 0 1 62.69291 164.0236 cm
q
0 0 0 rg
BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .474987 Tw (The first thing you should be aware of, it the fact that decorators have a performance penalty. The worse) Tj T* 0 Tw (case is shown by the following example:) Tj T* ET
@@ -3180,11 +3315,11 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 96 re B*
+n -6 -6 468.6898 72 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 74 Tm /F4 10 Tf 12 TL ($ cat performance.sh) Tj T* (python -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* ET
+BT 1 0 0 1 0 50 Tm /F4 10 Tf 12 TL ($ cat performance.sh) Tj T* (python -m timeit -s ") Tj T* (from decorator import decorator) Tj T* T* (@decorator) Tj T* ET
Q
Q
Q
@@ -3193,14 +3328,14 @@ Q
endstream
endobj
-% 'R92': class PDFStream
-92 0 obj
+% 'R97': class PDFStream
+97 0 obj
% page stream
-<< /Length 6135 >>
+<< /Length 6291 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 631.8236 cm
+1 0 0 1 62.69291 607.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -3210,24 +3345,24 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 132 re B*
+n -6 -6 468.6898 156 re B*
Q
q
0 0 0 rg
-BT 1 0 0 1 0 110 Tm /F4 10 Tf 12 TL T* (@do_nothing) Tj T* (def f\(\):) Tj T* ( pass) Tj T* (" "f\(\)") Tj T* T* (python -m timeit -s ") Tj T* (def f\(\):) Tj T* ( pass) Tj T* (" "f\(\)") Tj T* ET
+BT 1 0 0 1 0 134 Tm /F4 10 Tf 12 TL (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* (python -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 599.8236 cm
+1 0 0 1 62.69291 575.8236 cm
q
BT 1 0 0 1 0 14 Tm .266235 Tw 12 TL /F1 10 Tf 0 0 0 rg (On my MacBook, using the ) Tj /F4 10 Tf (do_nothing ) Tj /F1 10 Tf (decorator instead of the plain function is more than three times) Tj T* 0 Tw (slower:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 542.6236 cm
+1 0 0 1 62.69291 518.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -3248,20 +3383,20 @@ Q
Q
Q
q
-1 0 0 1 62.69291 498.6236 cm
+1 0 0 1 62.69291 474.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 /F4 10 Tf (f ) Tj /F1 10 Tf (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 468.6236 cm
+1 0 0 1 62.69291 444.6236 cm
q
0 0 0 rg
BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .867984 Tw (You should be aware that decorators will make your tracebacks longer and more difficult to understand.) Tj T* 0 Tw (Consider this example:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 411.4236 cm
+1 0 0 1 62.69291 387.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -3281,13 +3416,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 379.4236 cm
+1 0 0 1 62.69291 355.4236 cm
q
BT 1 0 0 1 0 14 Tm .583318 Tw 12 TL /F1 10 Tf 0 0 0 rg (Calling ) Tj /F4 10 Tf (f\(\) ) Tj /F1 10 Tf (will give you a ) Tj /F4 10 Tf (ZeroDivisionError) Tj /F1 10 Tf (, 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 250.2236 cm
+1 0 0 1 62.69291 226.2236 cm
q
q
1 0 0 1 0 0 cm
@@ -3307,13 +3442,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 182.2236 cm
+1 0 0 1 62.69291 158.2236 cm
q
-BT 1 0 0 1 0 50 Tm 1.05528 Tw 12 TL /F1 10 Tf 0 0 0 rg (You see here the inner call to the decorator ) Tj /F4 10 Tf (trace) Tj /F1 10 Tf (, which calls ) Tj /F4 10 Tf (f\(*args, **kw\)) Tj /F1 10 Tf (, and a reference to) Tj T* 0 Tw .265868 Tw /F4 10 Tf (File ") Tj (<) Tj (string) Tj (>) Tj (", line 2, in f) Tj /F1 10 Tf (. This latter reference is due to the fact that internally the decorator) Tj T* 0 Tw 2.053318 Tw (module uses ) Tj /F4 10 Tf (exec ) Tj /F1 10 Tf (to generate the decorated function. Notice that ) Tj /F4 10 Tf (exec ) Tj /F1 10 Tf (is ) Tj /F5 10 Tf (not ) Tj /F1 10 Tf (responsibile for the) Tj T* 0 Tw 1.507485 Tw (performance penalty, since is the called ) Tj /F5 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
+BT 1 0 0 1 0 50 Tm 1.05528 Tw 12 TL /F1 10 Tf 0 0 0 rg (You see here the inner call to the decorator ) Tj /F4 10 Tf (trace) Tj /F1 10 Tf (, which calls ) Tj /F4 10 Tf (f\(*args,) Tj ( ) Tj (**kw\)) Tj /F1 10 Tf (, and a reference to) Tj T* 0 Tw .076457 Tw /F4 10 Tf (File) Tj ( ) Tj (") Tj (<) Tj (string) Tj (>) Tj (",) Tj ( ) Tj (line) Tj ( ) Tj (2,) Tj ( ) Tj (in) Tj ( ) Tj (f) Tj /F1 10 Tf (. This latter reference is due to the fact that internally the decorator) Tj T* 0 Tw 2.053318 Tw (module uses ) Tj /F4 10 Tf (exec ) Tj /F1 10 Tf (to generate the decorated function. Notice that ) Tj /F4 10 Tf (exec ) Tj /F1 10 Tf (is ) Tj /F5 10 Tf (not ) Tj /F1 10 Tf (responsibile for the) Tj T* 0 Tw 1.507485 Tw (performance penalty, since is the called ) Tj /F5 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 104.2236 cm
+1 0 0 1 62.69291 80.22362 cm
q
BT 1 0 0 1 0 62 Tm .932209 Tw 12 TL /F1 10 Tf 0 0 0 rg (At present, there is no clean way to avoid ) Tj /F4 10 Tf (exec) Tj /F1 10 Tf (. A clean solution would require to change the CPython) Tj T* 0 Tw .777485 Tw (implementation of functions and add an hook to make it possible to change their signature directly. That) Tj T* 0 Tw .74186 Tw (could happen in future versions of Python \(see PEP ) Tj 0 0 .501961 rg (362) Tj 0 0 0 rg (\) and then the decorator module would become) Tj T* 0 Tw 2.385318 Tw (obsolete. However, at present, even in Python 3.1 it is impossible to change the function signature) Tj T* 0 Tw .931751 Tw (directly, therefore the ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (module is still useful. Actually, this is one of the main reasons why I) Tj T* 0 Tw (keep maintaining the module and releasing new versions.) Tj T* ET
Q
@@ -3321,10 +3456,10 @@ Q
endstream
endobj
-% 'R93': class PDFStream
-93 0 obj
+% 'R98': class PDFStream
+98 0 obj
% page stream
-<< /Length 7992 >>
+<< /Length 8028 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -3436,7 +3571,7 @@ Q
q
1 0 0 1 62.69291 240.2236 cm
q
-BT 1 0 0 1 0 26 Tm .194651 Tw 12 TL /F1 10 Tf 0 0 0 rg (Finally, the implementation is such that the decorated function attribute ) Tj /F4 10 Tf (.func_globals ) Tj /F1 10 Tf (is a ) Tj /F5 10 Tf (copy ) Tj /F1 10 Tf (of the) Tj T* 0 Tw 2.966136 Tw (original function attribute. Moreover the decorated function contains a ) Tj /F5 10 Tf (copy ) Tj /F1 10 Tf (of the original function) Tj T* 0 Tw (dictionary \() Tj /F4 10 Tf (vars\(decorated_f\) is not vars\(f\)) Tj /F1 10 Tf (\):) Tj T* ET
+BT 1 0 0 1 0 26 Tm .194651 Tw 12 TL /F1 10 Tf 0 0 0 rg (Finally, the implementation is such that the decorated function attribute ) Tj /F4 10 Tf (.func_globals ) Tj /F1 10 Tf (is a ) Tj /F5 10 Tf (copy ) Tj /F1 10 Tf (of the) Tj T* 0 Tw 2.966136 Tw (original function attribute. Moreover the decorated function contains a ) Tj /F5 10 Tf (copy ) Tj /F1 10 Tf (of the original function) Tj T* 0 Tw (dictionary \() Tj /F4 10 Tf (vars\(decorated_f\)) Tj ( ) Tj (is) Tj ( ) Tj (not) Tj ( ) Tj (vars\(f\)) Tj /F1 10 Tf (\):) Tj T* ET
Q
Q
q
@@ -3462,8 +3597,8 @@ Q
endstream
endobj
-% 'R94': class PDFStream
-94 0 obj
+% 'R99': class PDFStream
+99 0 obj
% page stream
<< /Length 6552 >>
stream
@@ -3562,124 +3697,132 @@ Q
endstream
endobj
-% 'R95': class PDFPageLabels
-95 0 obj
+% 'R100': class PDFPageLabels
+100 0 obj
% Document Root
<< /Nums [ 0
- 96 0 R
+ 101 0 R
1
- 97 0 R
+ 102 0 R
2
- 98 0 R
+ 103 0 R
3
- 99 0 R
+ 104 0 R
4
- 100 0 R
+ 105 0 R
5
- 101 0 R
+ 106 0 R
6
- 102 0 R
+ 107 0 R
7
- 103 0 R
+ 108 0 R
8
- 104 0 R
+ 109 0 R
9
- 105 0 R
+ 110 0 R
10
- 106 0 R
+ 111 0 R
11
- 107 0 R
+ 112 0 R
12
- 108 0 R
+ 113 0 R
13
- 109 0 R ] >>
+ 114 0 R
+ 14
+ 115 0 R ] >>
endobj
-% 'R96': class PDFPageLabel
-96 0 obj
+% 'R101': class PDFPageLabel
+101 0 obj
% None
<< /S /D
/St 1 >>
endobj
-% 'R97': class PDFPageLabel
-97 0 obj
+% 'R102': class PDFPageLabel
+102 0 obj
% None
<< /S /D
/St 2 >>
endobj
-% 'R98': class PDFPageLabel
-98 0 obj
+% 'R103': class PDFPageLabel
+103 0 obj
% None
<< /S /D
/St 3 >>
endobj
-% 'R99': class PDFPageLabel
-99 0 obj
+% 'R104': class PDFPageLabel
+104 0 obj
% None
<< /S /D
/St 4 >>
endobj
-% 'R100': class PDFPageLabel
-100 0 obj
+% 'R105': class PDFPageLabel
+105 0 obj
% None
<< /S /D
/St 5 >>
endobj
-% 'R101': class PDFPageLabel
-101 0 obj
+% 'R106': class PDFPageLabel
+106 0 obj
% None
<< /S /D
/St 6 >>
endobj
-% 'R102': class PDFPageLabel
-102 0 obj
+% 'R107': class PDFPageLabel
+107 0 obj
% None
<< /S /D
/St 7 >>
endobj
-% 'R103': class PDFPageLabel
-103 0 obj
+% 'R108': class PDFPageLabel
+108 0 obj
% None
<< /S /D
/St 8 >>
endobj
-% 'R104': class PDFPageLabel
-104 0 obj
+% 'R109': class PDFPageLabel
+109 0 obj
% None
<< /S /D
/St 9 >>
endobj
-% 'R105': class PDFPageLabel
-105 0 obj
+% 'R110': class PDFPageLabel
+110 0 obj
% None
<< /S /D
/St 10 >>
endobj
-% 'R106': class PDFPageLabel
-106 0 obj
+% 'R111': class PDFPageLabel
+111 0 obj
% None
<< /S /D
/St 11 >>
endobj
-% 'R107': class PDFPageLabel
-107 0 obj
+% 'R112': class PDFPageLabel
+112 0 obj
% None
<< /S /D
/St 12 >>
endobj
-% 'R108': class PDFPageLabel
-108 0 obj
+% 'R113': class PDFPageLabel
+113 0 obj
% None
<< /S /D
/St 13 >>
endobj
-% 'R109': class PDFPageLabel
-109 0 obj
+% 'R114': class PDFPageLabel
+114 0 obj
% None
<< /S /D
/St 14 >>
endobj
+% 'R115': class PDFPageLabel
+115 0 obj
+% None
+<< /S /D
+ /St 15 >>
+endobj
xref
-0 110
+0 116
0000000000 65535 f
0000000113 00000 n
0000000271 00000 n
@@ -3716,88 +3859,94 @@ xref
0000007534 00000 n
0000007777 00000 n
0000008020 00000 n
-0000008247 00000 n
-0000008807 00000 n
-0000009002 00000 n
-0000009271 00000 n
-0000009531 00000 n
-0000009843 00000 n
-0000010019 00000 n
-0000010299 00000 n
-0000010579 00000 n
-0000010859 00000 n
-0000011139 00000 n
-0000011419 00000 n
-0000011714 00000 n
-0000011954 00000 n
-0000012270 00000 n
-0000012538 00000 n
-0000012840 00000 n
-0000013135 00000 n
-0000013380 00000 n
-0000013682 00000 n
-0000013977 00000 n
-0000014237 00000 n
-0000014497 00000 n
-0000014755 00000 n
-0000015007 00000 n
-0000015247 00000 n
-0000015554 00000 n
-0000015901 00000 n
-0000016060 00000 n
-0000016345 00000 n
-0000016471 00000 n
-0000016644 00000 n
-0000016831 00000 n
-0000017031 00000 n
-0000017219 00000 n
-0000017412 00000 n
-0000017611 00000 n
-0000017795 00000 n
-0000017976 00000 n
-0000018175 00000 n
-0000018375 00000 n
-0000018587 00000 n
-0000018787 00000 n
-0000018983 00000 n
-0000019135 00000 n
-0000019361 00000 n
-0000028620 00000 n
-0000034875 00000 n
-0000041765 00000 n
-0000048623 00000 n
-0000057355 00000 n
-0000063280 00000 n
-0000066953 00000 n
-0000074640 00000 n
-0000082130 00000 n
-0000087568 00000 n
-0000092034 00000 n
-0000098268 00000 n
-0000106359 00000 n
-0000113014 00000 n
-0000113290 00000 n
-0000113367 00000 n
-0000113444 00000 n
-0000113521 00000 n
-0000113599 00000 n
-0000113678 00000 n
-0000113757 00000 n
-0000113836 00000 n
-0000113915 00000 n
-0000113994 00000 n
-0000114074 00000 n
-0000114154 00000 n
-0000114234 00000 n
-0000114314 00000 n
+0000008263 00000 n
+0000008506 00000 n
+0000008733 00000 n
+0000009311 00000 n
+0000009506 00000 n
+0000009762 00000 n
+0000009953 00000 n
+0000010213 00000 n
+0000010523 00000 n
+0000010803 00000 n
+0000011083 00000 n
+0000011363 00000 n
+0000011643 00000 n
+0000011923 00000 n
+0000012203 00000 n
+0000012484 00000 n
+0000012779 00000 n
+0000013034 00000 n
+0000013302 00000 n
+0000013613 00000 n
+0000013908 00000 n
+0000014153 00000 n
+0000014455 00000 n
+0000014750 00000 n
+0000015010 00000 n
+0000015270 00000 n
+0000015528 00000 n
+0000015780 00000 n
+0000016020 00000 n
+0000016327 00000 n
+0000016674 00000 n
+0000016834 00000 n
+0000017119 00000 n
+0000017245 00000 n
+0000017418 00000 n
+0000017605 00000 n
+0000017805 00000 n
+0000017993 00000 n
+0000018186 00000 n
+0000018385 00000 n
+0000018569 00000 n
+0000018750 00000 n
+0000018940 00000 n
+0000019140 00000 n
+0000019340 00000 n
+0000019552 00000 n
+0000019752 00000 n
+0000019948 00000 n
+0000020100 00000 n
+0000020335 00000 n
+0000029480 00000 n
+0000037125 00000 n
+0000045281 00000 n
+0000052495 00000 n
+0000061446 00000 n
+0000068701 00000 n
+0000076181 00000 n
+0000083501 00000 n
+0000090780 00000 n
+0000098681 00000 n
+0000106059 00000 n
+0000113304 00000 n
+0000119694 00000 n
+0000127821 00000 n
+0000134477 00000 n
+0000134774 00000 n
+0000134853 00000 n
+0000134932 00000 n
+0000135011 00000 n
+0000135090 00000 n
+0000135169 00000 n
+0000135248 00000 n
+0000135327 00000 n
+0000135406 00000 n
+0000135485 00000 n
+0000135565 00000 n
+0000135645 00000 n
+0000135725 00000 n
+0000135805 00000 n
+0000135885 00000 n
trailer
<< /ID
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
- [(\242&\312y\310\003\262\266a\026\016\305\226\207\2755) (\242&\312y\310\003\262\266a\026\016\305\226\207\2755)]
+ [(%\2119\\+X\235\026\270\000 \364\017F\214k) (%\2119\\+X\235\026\270\000 \364\017F\214k)]
- /Info 64 0 R
- /Root 63 0 R
- /Size 110 >>
+ /Info 67 0 R
+ /Root 66 0 R
+ /Size 116 >>
startxref
-114363
+135934
%%EOF
diff --git a/decorator/documentation.py b/decorator/documentation.py
index 8bdcf04..3d5a5c0 100644
--- a/decorator/documentation.py
+++ b/decorator/documentation.py
@@ -340,18 +340,16 @@ We have just seen an examples of a simple decorator factory,
implemented as a function returning a decorator.
For more complex situations, it is more
convenient to implement decorator factories as classes returning
-callable objects that can be used as signature-preserving
-decorators. The suggested pattern to do that is to introduce
-a helper method ``call(self, func, *args, **kw)`` and to call
-it in the ``__call__(self, func)`` method.
+callable objects that can be converted into decorators.
-As an example, here I show a decorator
+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. Moreover, it is possible to set
three callbacks ``on_success``, ``on_failure`` and ``on_closing``,
-to specify how to manage the function call.
-The implementation is the following:
+to specify how to manage the function call (of course the code here
+is just an example, it is not a recommended way of doing multi-threaded
+programming). The implementation is the following:
$$on_success
$$on_failure
@@ -369,7 +367,7 @@ be locked. Here is a minimalistic example:
.. code-block:: python
- >>> async = Async(threading.Thread)
+ >>> async = decorator(Async(threading.Thread))
>>> datalist = [] # for simplicity the written data are stored into a list.
@@ -399,6 +397,71 @@ be no synchronization problems since ``write`` is locked.
>>> print datalist
['data1', 'data2']
+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
+
+ >>> ba = before_after('BEFORE', 'AFTER')
+ >>> type(ba)
+ <class 'contextlib.GeneratorContextManager'>
+ >>> with ba:
+ ... 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; 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 even in Python 2.5.
+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
---------------------------------------------------------------
@@ -862,29 +925,28 @@ class Async(object):
async_with_processes = Async(multiprocessing.Process)
"""
- def __init__(self, threadfactory):
- self.threadfactory = threadfactory
-
- def __call__(self, func, on_success=on_success,
+ def __init__(self, threadfactory, on_success=on_success,
on_failure=on_failure, on_closing=on_closing):
- # every decorated function has its own independent thread counter
- func.counter = itertools.count(1)
- func.on_success = on_success
- func.on_failure = on_failure
- func.on_closing = on_closing
- return decorator(self.call, func)
-
- def call(self, func, *args, **kw):
+ self.threadfactory = threadfactory
+ self.on_success = on_success
+ self.on_failure = on_failure
+ self.on_closing = on_closing
+
+ def __call__(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__, counter.next())
def func_wrapper():
try:
result = func(*args, **kw)
except:
- func.on_failure(sys.exc_info())
+ self.on_failure(sys.exc_info())
else:
- return func.on_success(result)
+ return self.on_success(result)
finally:
- func.on_closing()
- name = '%s-%s' % (func.__name__, func.counter.next())
+ self.on_closing()
thread = self.threadfactory(None, func_wrapper, name)
thread.start()
return thread
@@ -1048,5 +1110,25 @@ def a_test_for_pylons():
'The good old factorial'
"""
+@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)
+
if __name__ == '__main__':
import doctest; doctest.testmod()
diff --git a/decorator/documentation3.html b/decorator/documentation3.html
index 0de7917..c5e2fac 100644
--- a/decorator/documentation3.html
+++ b/decorator/documentation3.html
@@ -3,7 +3,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="generator" content="Docutils 0.7: http://docutils.sourceforge.net/" />
+<meta name="generator" content="Docutils 0.8.1: http://docutils.sourceforge.net/" />
<title>The decorator module</title>
<meta name="author" content="Michele Simionato" />
<style type="text/css">
@@ -83,10 +83,10 @@
<tr class="field"><th class="docinfo-name">E-mail:</th><td class="field-body"><a class="reference external" href="mailto:michele.simionato&#64;gmail.com">michele.simionato&#64;gmail.com</a></td>
</tr>
<tr><th class="docinfo-name">Version:</th>
-<td>3.3.2 (2011-11-09)</td></tr>
+<td>3.4.0 (2012-10-18)</td></tr>
<tr class="field"><th class="docinfo-name">Requires:</th><td class="field-body">Python 2.4+</td>
</tr>
-<tr class="field"><th class="docinfo-name">Download page:</th><td class="field-body"><a class="reference external" href="http://pypi.python.org/pypi/decorator/3.3.2">http://pypi.python.org/pypi/decorator/3.3.2</a></td>
+<tr class="field"><th class="docinfo-name">Download page:</th><td class="field-body"><a class="reference external" href="http://pypi.python.org/pypi/decorator/3.4.0">http://pypi.python.org/pypi/decorator/3.4.0</a></td>
</tr>
<tr class="field"><th class="docinfo-name">Installation:</th><td class="field-body"><tt class="docutils literal">easy_install decorator</tt></td>
</tr>
@@ -106,12 +106,13 @@
<li><a class="reference internal" href="#decorator-is-a-decorator" id="id10"><tt class="docutils literal">decorator</tt> is a decorator</a></li>
<li><a class="reference internal" href="#blocking" id="id11"><tt class="docutils literal">blocking</tt></a></li>
<li><a class="reference internal" href="#async" id="id12"><tt class="docutils literal">async</tt></a></li>
-<li><a class="reference internal" href="#the-functionmaker-class" id="id13">The <tt class="docutils literal">FunctionMaker</tt> class</a></li>
-<li><a class="reference internal" href="#getting-the-source-code" id="id14">Getting the source code</a></li>
-<li><a class="reference internal" href="#dealing-with-third-party-decorators" id="id15">Dealing with third party decorators</a></li>
-<li><a class="reference internal" href="#caveats-and-limitations" id="id16">Caveats and limitations</a></li>
-<li><a class="reference internal" href="#compatibility-notes" id="id17">Compatibility notes</a></li>
-<li><a class="reference internal" href="#licence" id="id18">LICENCE</a></li>
+<li><a class="reference internal" href="#contextmanager" id="id13">contextmanager</a></li>
+<li><a class="reference internal" href="#the-functionmaker-class" id="id14">The <tt class="docutils literal">FunctionMaker</tt> class</a></li>
+<li><a class="reference internal" href="#getting-the-source-code" id="id15">Getting the source code</a></li>
+<li><a class="reference internal" href="#dealing-with-third-party-decorators" id="id16">Dealing with third party decorators</a></li>
+<li><a class="reference internal" href="#caveats-and-limitations" id="id17">Caveats and limitations</a></li>
+<li><a class="reference internal" href="#compatibility-notes" id="id18">Compatibility notes</a></li>
+<li><a class="reference internal" href="#licence" id="id19">LICENCE</a></li>
</ul>
</div>
<div class="section" id="introduction">
@@ -316,7 +317,8 @@ decorate to the caller function.</p>
function is called:</p>
<div class="codeblock python">
<div class="highlight"><pre><span class="k">def</span> <span class="nf">_trace</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
- <span class="k">print</span><span class="p">(</span><span class="s">&quot;calling </span><span class="si">%s</span><span class="s"> with args </span><span class="si">%s</span><span class="s">, </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">__name__</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kw</span><span class="p">))</span>
+ <span class="n">kwstr</span> <span class="o">=</span> <span class="s">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s">&#39;</span><span class="si">%r</span><span class="s">: </span><span class="si">%r</span><span class="s">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">kw</span><span class="p">[</span><span class="n">k</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">kw</span><span class="p">))</span>
+ <span class="k">print</span><span class="p">(</span><span class="s">&quot;calling </span><span class="si">%s</span><span class="s"> with args </span><span class="si">%s</span><span class="s">, {</span><span class="si">%s</span><span class="s">}&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">__name__</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwstr</span><span class="p">))</span>
<span class="k">return</span> <span class="n">f</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>
</pre></div>
@@ -395,9 +397,6 @@ utility <tt class="docutils literal">inspect.getfullargspec</tt>, new in Python
<span class="o">&gt;&gt;&gt;</span> <span class="n">argspec</span><span class="o">.</span><span class="n">kwonlyargs</span>
<span class="p">[]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">argspec</span><span class="o">.</span><span class="n">kwonlydefaults</span>
-<span class="o">&gt;&gt;&gt;</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">argspec</span><span class="o">.</span><span class="n">annotations</span><span class="o">.</span><span class="n">items</span><span class="p">())</span>
-<span class="p">[(</span><span class="s">&#39;args&#39;</span><span class="p">,</span> <span class="s">&#39;varargs&#39;</span><span class="p">),</span> <span class="p">(</span><span class="s">&#39;kw&#39;</span><span class="p">,</span> <span class="s">&#39;kwargs&#39;</span><span class="p">),</span> <span class="p">(</span><span class="s">&#39;x&#39;</span><span class="p">,</span> <span class="s">&#39;the first argument&#39;</span><span class="p">),</span> <span class="p">(</span><span class="s">&#39;y&#39;</span><span class="p">,</span>
-<span class="s">&#39;default argument&#39;</span><span class="p">)]</span>
</pre></div>
</div>
@@ -408,16 +407,9 @@ utility <tt class="docutils literal">inspect.getfullargspec</tt>, new in Python
</pre></div>
</div>
-<p>The two dictionaries are different objects, though</p>
-<div class="codeblock python">
-<div class="highlight"><pre><span class="o">&gt;&gt;&gt;</span> <span class="nb">id</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">__annotations__</span><span class="p">)</span> <span class="o">!=</span> <span class="nb">id</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">__wrapped__</span><span class="o">.</span><span class="n">__annotations__</span><span class="p">)</span>
-<span class="bp">True</span>
-</pre></div>
-
-</div>
-<p>since internally the decorator module creates an entirely new dictionary
-(it is not simply attaching the <tt class="docutils literal">__annotations__</tt> attribute to the new
-function).</p>
+<p>Depending on the version of the decorator module, the two dictionaries can
+be the same object or not: you cannot rely on object identity, but you can
+rely on the content being the same.</p>
</div>
<div class="section" id="decorator-is-a-decorator">
<h1><a class="toc-backref" href="#id10"><tt class="docutils literal">decorator</tt> is a decorator</a></h1>
@@ -437,7 +429,8 @@ For instance, you can write directly</p>
<div class="codeblock python">
<div class="highlight"><pre><span class="o">&gt;&gt;&gt;</span> <span class="nd">@decorator</span>
<span class="o">...</span> <span class="k">def</span> <span class="nf">trace</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
-<span class="o">...</span> <span class="k">print</span><span class="p">(</span><span class="s">&quot;calling </span><span class="si">%s</span><span class="s"> with args </span><span class="si">%s</span><span class="s">, </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">__name__</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kw</span><span class="p">))</span>
+<span class="o">...</span> <span class="n">kwstr</span> <span class="o">=</span> <span class="s">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s">&#39;</span><span class="si">%r</span><span class="s">: </span><span class="si">%r</span><span class="s">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">kw</span><span class="p">[</span><span class="n">k</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">kw</span><span class="p">))</span>
+<span class="o">...</span> <span class="k">print</span><span class="p">(</span><span class="s">&quot;calling </span><span class="si">%s</span><span class="s"> with args </span><span class="si">%s</span><span class="s">, {</span><span class="si">%s</span><span class="s">}&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">__name__</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwstr</span><span class="p">))</span>
<span class="o">...</span> <span class="k">return</span> <span class="n">f</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>
</pre></div>
@@ -520,17 +513,15 @@ available. For instance:</p>
implemented as a function returning a decorator.
For more complex situations, it is more
convenient to implement decorator factories as classes returning
-callable objects that can be used as signature-preserving
-decorators. The suggested pattern to do that is to introduce
-a helper method <tt class="docutils literal">call(self, func, *args, **kw)</tt> and to call
-it in the <tt class="docutils literal">__call__(self, func)</tt> method.</p>
-<p>As an example, here I show a decorator
+callable objects that can be converted into decorators.</p>
+<p>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. Moreover, it is possible to set
three callbacks <tt class="docutils literal">on_success</tt>, <tt class="docutils literal">on_failure</tt> and <tt class="docutils literal">on_closing</tt>,
-to specify how to manage the function call.
-The implementation is the following:</p>
+to specify how to manage the function call (of course the code here
+is just an example, it is not a recommended way of doing multi-threaded
+programming). The implementation is the following:</p>
<div class="codeblock python">
<div class="highlight"><pre><span class="k">def</span> <span class="nf">on_success</span><span class="p">(</span><span class="n">result</span><span class="p">):</span> <span class="c"># default implementation</span>
<span class="s">&quot;Called on the result of the function&quot;</span>
@@ -562,29 +553,28 @@ The implementation is the following:</p>
<span class="sd"> async_with_processes = Async(multiprocessing.Process)</span>
<span class="sd"> &quot;&quot;&quot;</span>
- <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">threadfactory</span><span class="p">):</span>
- <span class="bp">self</span><span class="o">.</span><span class="n">threadfactory</span> <span class="o">=</span> <span class="n">threadfactory</span>
-
- <span class="k">def</span> <span class="nf">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">func</span><span class="p">,</span> <span class="n">on_success</span><span class="o">=</span><span class="n">on_success</span><span class="p">,</span>
+ <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">threadfactory</span><span class="p">,</span> <span class="n">on_success</span><span class="o">=</span><span class="n">on_success</span><span class="p">,</span>
<span class="n">on_failure</span><span class="o">=</span><span class="n">on_failure</span><span class="p">,</span> <span class="n">on_closing</span><span class="o">=</span><span class="n">on_closing</span><span class="p">):</span>
- <span class="c"># every decorated function has its own independent thread counter</span>
- <span class="n">func</span><span class="o">.</span><span class="n">counter</span> <span class="o">=</span> <span class="n">itertools</span><span class="o">.</span><span class="n">count</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
- <span class="n">func</span><span class="o">.</span><span class="n">on_success</span> <span class="o">=</span> <span class="n">on_success</span>
- <span class="n">func</span><span class="o">.</span><span class="n">on_failure</span> <span class="o">=</span> <span class="n">on_failure</span>
- <span class="n">func</span><span class="o">.</span><span class="n">on_closing</span> <span class="o">=</span> <span class="n">on_closing</span>
- <span class="k">return</span> <span class="n">decorator</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">,</span> <span class="n">func</span><span class="p">)</span>
-
- <span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">func</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">threadfactory</span> <span class="o">=</span> <span class="n">threadfactory</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">on_success</span> <span class="o">=</span> <span class="n">on_success</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">on_failure</span> <span class="o">=</span> <span class="n">on_failure</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">on_closing</span> <span class="o">=</span> <span class="n">on_closing</span>
+
+ <span class="k">def</span> <span class="nf">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">func</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">counter</span> <span class="o">=</span> <span class="n">func</span><span class="o">.</span><span class="n">counter</span>
+ <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span> <span class="c"># instantiate the counter at the first call</span>
+ <span class="n">counter</span> <span class="o">=</span> <span class="n">func</span><span class="o">.</span><span class="n">counter</span> <span class="o">=</span> <span class="n">itertools</span><span class="o">.</span><span class="n">count</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
+ <span class="n">name</span> <span class="o">=</span> <span class="s">&#39;</span><span class="si">%s</span><span class="s">-</span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">func</span><span class="o">.</span><span class="n">__name__</span><span class="p">,</span> <span class="nb">next</span><span class="p">(</span><span class="n">counter</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">func_wrapper</span><span class="p">():</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>
<span class="k">except</span><span class="p">:</span>
- <span class="n">func</span><span class="o">.</span><span class="n">on_failure</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">exc_info</span><span class="p">())</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">on_failure</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">exc_info</span><span class="p">())</span>
<span class="k">else</span><span class="p">:</span>
- <span class="k">return</span> <span class="n">func</span><span class="o">.</span><span class="n">on_success</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
+ <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">on_success</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<span class="k">finally</span><span class="p">:</span>
- <span class="n">func</span><span class="o">.</span><span class="n">on_closing</span><span class="p">()</span>
- <span class="n">name</span> <span class="o">=</span> <span class="s">&#39;</span><span class="si">%s</span><span class="s">-</span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">func</span><span class="o">.</span><span class="n">__name__</span><span class="p">,</span> <span class="nb">next</span><span class="p">(</span><span class="n">func</span><span class="o">.</span><span class="n">counter</span><span class="p">))</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">on_closing</span><span class="p">()</span>
<span class="n">thread</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">threadfactory</span><span class="p">(</span><span class="bp">None</span><span class="p">,</span> <span class="n">func_wrapper</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
<span class="n">thread</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
<span class="k">return</span> <span class="n">thread</span>
@@ -599,7 +589,7 @@ an external resource which can be accessed by a single user at once
(for instance a printer). Then the access to the writing function must
be locked. Here is a minimalistic example:</p>
<div class="codeblock python">
-<div class="highlight"><pre><span class="o">&gt;&gt;&gt;</span> <span class="n">async</span> <span class="o">=</span> <span class="n">Async</span><span class="p">(</span><span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">)</span>
+<div class="highlight"><pre><span class="o">&gt;&gt;&gt;</span> <span class="n">async</span> <span class="o">=</span> <span class="n">decorator</span><span class="p">(</span><span class="n">Async</span><span class="p">(</span><span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">))</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">datalist</span> <span class="o">=</span> <span class="p">[]</span> <span class="c"># for simplicity the written data are stored into a list.</span>
@@ -632,8 +622,72 @@ be no synchronization problems since <tt class="docutils literal">write</tt> is
</div>
</div>
+<div class="section" id="contextmanager">
+<h1><a class="toc-backref" href="#id13">contextmanager</a></h1>
+<p>For a long time Python had in its standard library a <tt class="docutils literal">contextmanager</tt>
+decorator, able to convert generator functions into
+<tt class="docutils literal">_GeneratorContextManager</tt>
+factories. For instance if you write</p>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">contextlib</span> <span class="kn">import</span> <span class="n">contextmanager</span>
+<span class="o">&gt;&gt;&gt;</span> <span class="nd">@contextmanager</span>
+<span class="o">...</span> <span class="k">def</span> <span class="nf">before_after</span><span class="p">(</span><span class="n">before</span><span class="p">,</span> <span class="n">after</span><span class="p">):</span>
+<span class="o">...</span> <span class="k">print</span><span class="p">(</span><span class="n">before</span><span class="p">)</span>
+<span class="o">...</span> <span class="k">yield</span>
+<span class="o">...</span> <span class="k">print</span><span class="p">(</span><span class="n">after</span><span class="p">)</span>
+</pre></div>
+
+</div>
+<p>then <tt class="docutils literal">before_after</tt> is a factory function returning
+<tt class="docutils literal">_GeneratorContextManager</tt> objects which can be used with
+the <tt class="docutils literal">with</tt> statement:</p>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="o">&gt;&gt;&gt;</span> <span class="n">ba</span> <span class="o">=</span> <span class="n">before_after</span><span class="p">(</span><span class="s">&#39;BEFORE&#39;</span><span class="p">,</span> <span class="s">&#39;AFTER&#39;</span><span class="p">)</span>
+<span class="o">&gt;&gt;&gt;</span> <span class="nb">type</span><span class="p">(</span><span class="n">ba</span><span class="p">)</span>
+<span class="o">&lt;</span><span class="k">class</span> <span class="err">&#39;</span><span class="nc">contextlib</span><span class="o">.</span><span class="n">_GeneratorContextManager</span><span class="s">&#39;&gt;</span>
+<span class="o">&gt;&gt;&gt;</span> <span class="k">with</span> <span class="n">ba</span><span class="p">:</span>
+<span class="o">...</span> <span class="k">print</span><span class="p">(</span><span class="s">&#39;hello&#39;</span><span class="p">)</span>
+<span class="n">BEFORE</span>
+<span class="n">hello</span>
+<span class="n">AFTER</span>
+</pre></div>
+
+</div>
+<p>Basically, it is as if the content of the <tt class="docutils literal">with</tt> block was executed
+in the place of the <tt class="docutils literal">yield</tt> expression in the generator function.
+In Python 3.2 <tt class="docutils literal">_GeneratorContextManager</tt>
+objects were enhanced with a <tt class="docutils literal">__call__</tt>
+method, so that they can be used as decorators as in this example:</p>
+<div class="codeblock python">
+<div class="highlight"><pre><span class="o">&gt;&gt;&gt;</span> <span class="nd">@ba</span>
+<span class="o">...</span> <span class="k">def</span> <span class="nf">hello</span><span class="p">():</span>
+<span class="o">...</span> <span class="k">print</span><span class="p">(</span><span class="s">&#39;hello&#39;</span><span class="p">)</span>
+<span class="o">...</span>
+<span class="o">&gt;&gt;&gt;</span> <span class="n">hello</span><span class="p">()</span>
+<span class="n">BEFORE</span>
+<span class="n">hello</span>
+<span class="n">AFTER</span>
+</pre></div>
+
+</div>
+<p>The <tt class="docutils literal">ba</tt> decorator is basically inserting a <tt class="docutils literal">with ba:</tt>
+block inside the function.
+However there two issues: the first is that <tt class="docutils literal">_GeneratorContextManager</tt>
+objects are callable only in Python 3.2, so the previous example will break
+in older versions of Python; the second is that
+<tt class="docutils literal">_GeneratorContextManager</tt> objects do not preserve the signature
+of the decorated functions: the decorated <tt class="docutils literal">hello</tt> function here will have
+a generic signature <tt class="docutils literal"><span class="pre">hello(*args,</span> **kwargs)</tt> but will break when
+called with more than zero arguments. For such reasons the decorator
+module, starting with release 3.4, offers a <tt class="docutils literal">decorator.contextmanager</tt>
+decorator that solves both problems and works even in Python 2.5.
+The usage is the same and factories decorated with <tt class="docutils literal">decorator.contextmanager</tt>
+will returns instances of <tt class="docutils literal">ContextManager</tt>, a subclass of
+<tt class="docutils literal">contextlib._GeneratorContextManager</tt> with a <tt class="docutils literal">__call__</tt> method
+acting as a signature-preserving decorator.</p>
+</div>
<div class="section" id="the-functionmaker-class">
-<h1><a class="toc-backref" href="#id13">The <tt class="docutils literal">FunctionMaker</tt> class</a></h1>
+<h1><a class="toc-backref" href="#id14">The <tt class="docutils literal">FunctionMaker</tt> class</a></h1>
<p>You may wonder about how the functionality of the <tt class="docutils literal">decorator</tt> module
is implemented. The basic building block is
a <tt class="docutils literal">FunctionMaker</tt> class which is able to generate on the fly
@@ -705,7 +759,7 @@ On the other hand, the functionality provided by
stay there forever.</p>
</div>
<div class="section" id="getting-the-source-code">
-<h1><a class="toc-backref" href="#id14">Getting the source code</a></h1>
+<h1><a class="toc-backref" href="#id15">Getting the source code</a></h1>
<p>Internally <tt class="docutils literal">FunctionMaker.create</tt> uses <tt class="docutils literal">exec</tt> to generate the
decorated function. Therefore
<tt class="docutils literal">inspect.getsource</tt> will not work for decorated functions. That
@@ -754,7 +808,7 @@ undecorated function:</p>
</div>
</div>
<div class="section" id="dealing-with-third-party-decorators">
-<h1><a class="toc-backref" href="#id15">Dealing with third party decorators</a></h1>
+<h1><a class="toc-backref" href="#id16">Dealing with third party decorators</a></h1>
<p>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
@@ -860,7 +914,7 @@ making a recursive call, or returns directly the result of a recursive
call).</p>
</div>
<div class="section" id="caveats-and-limitations">
-<h1><a class="toc-backref" href="#id16">Caveats and limitations</a></h1>
+<h1><a class="toc-backref" href="#id17">Caveats and limitations</a></h1>
<p>The first thing you should be aware of, it the fact that decorators
have a performance penalty.
The worse case is shown by the following example:</p>
@@ -931,7 +985,7 @@ would require to change the CPython implementation of functions and
add an hook to make it possible to change their signature directly.
That could happen in future versions of Python (see PEP <a class="reference external" href="http://www.python.org/dev/peps/pep-0362">362</a>) and
then the decorator module would become obsolete. However, at present,
-even in Python 3.1 it is impossible to change the function signature
+even in Python 3.2 it is impossible to change the function signature
directly, therefore the <tt class="docutils literal">decorator</tt> module is still useful.
Actually, this is one of the main reasons why I keep maintaining
the module and releasing new versions.</p>
@@ -974,7 +1028,7 @@ a <em>copy</em> of the original function dictionary
</div>
</div>
<div class="section" id="compatibility-notes">
-<h1><a class="toc-backref" href="#id17">Compatibility notes</a></h1>
+<h1><a class="toc-backref" href="#id18">Compatibility notes</a></h1>
<p>Version 3.3 is the first version of the <tt class="docutils literal">decorator</tt> module to fully
support Python 3, including <a class="reference external" href="http://www.python.org/dev/peps/pep-3107/">function annotations</a>. Version 3.2 was the
first version to support Python 3 via the <tt class="docutils literal">2to3</tt> conversion tool
@@ -1014,7 +1068,7 @@ tuple. That means that running the file
they are not serious.</p>
</div>
<div class="section" id="licence">
-<h1><a class="toc-backref" href="#id18">LICENCE</a></h1>
+<h1><a class="toc-backref" href="#id19">LICENCE</a></h1>
<p>Copyright (c) 2005-2012, Michele Simionato
All rights reserved.</p>
<p>Redistribution and use in source and binary forms, with or without
diff --git a/decorator/documentation3.pdf b/decorator/documentation3.pdf
index 53dbc33..ffdcc6c 100644
--- a/decorator/documentation3.pdf
+++ b/decorator/documentation3.pdf
@@ -1,5 +1,5 @@
%PDF-1.4
-%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
+%���� ReportLab Generated PDF document http://www.reportlab.com
% 'BasicFonts': class PDFDictionary
1 0 obj
% The standard fonts dictionary
@@ -7,8 +7,8 @@
/F2 3 0 R
/F3 4 0 R
/F4 7 0 R
- /F5 39 0 R
- /F6 41 0 R >>
+ /F5 41 0 R
+ /F6 43 0 R >>
endobj
% 'F1': class PDFType1Font
2 0 obj
@@ -56,7 +56,7 @@ endobj
6 0 obj
<< /A << /S /URI
/Type /Action
- /URI (http://pypi.python.org/pypi/decorator/3.3.2) >>
+ /URI (http://pypi.python.org/pypi/decorator/3.4.0) >>
/Border [ 0
0
0 ]
@@ -82,10 +82,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 38 0 R
+ /Dest [ 40 0 R
/XYZ
62.69291
- 293.0236
+ 275.0236
0 ]
/Rect [ 62.69291
560.7736
@@ -100,10 +100,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 38 0 R
+ /Dest [ 40 0 R
/XYZ
62.69291
- 293.0236
+ 275.0236
0 ]
/Rect [ 527.0227
560.7736
@@ -118,10 +118,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 43 0 R
+ /Dest [ 45 0 R
/XYZ
62.69291
- 675.0236
+ 657.0236
0 ]
/Rect [ 62.69291
542.7736
@@ -136,10 +136,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 43 0 R
+ /Dest [ 45 0 R
/XYZ
62.69291
- 675.0236
+ 657.0236
0 ]
/Rect [ 527.0227
542.7736
@@ -154,10 +154,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 43 0 R
+ /Dest [ 45 0 R
/XYZ
62.69291
- 438.0236
+ 420.0236
0 ]
/Rect [ 62.69291
524.7736
@@ -172,10 +172,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 43 0 R
+ /Dest [ 45 0 R
/XYZ
62.69291
- 438.0236
+ 420.0236
0 ]
/Rect [ 527.0227
524.7736
@@ -190,10 +190,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 44 0 R
+ /Dest [ 46 0 R
/XYZ
62.69291
- 427.4236
+ 409.4236
0 ]
/Rect [ 62.69291
506.7736
@@ -208,10 +208,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 44 0 R
+ /Dest [ 46 0 R
/XYZ
62.69291
- 427.4236
+ 409.4236
0 ]
/Rect [ 527.0227
506.7736
@@ -226,7 +226,7 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 45 0 R
+ /Dest [ 47 0 R
/XYZ
62.69291
435.4236
@@ -244,7 +244,7 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 45 0 R
+ /Dest [ 47 0 R
/XYZ
62.69291
435.4236
@@ -262,7 +262,7 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 47 0 R
+ /Dest [ 49 0 R
/XYZ
62.69291
567.978
@@ -280,7 +280,7 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 47 0 R
+ /Dest [ 49 0 R
/XYZ
62.69291
567.978
@@ -298,10 +298,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 48 0 R
+ /Dest [ 50 0 R
/XYZ
62.69291
- 683.8236
+ 765.0236
0 ]
/Rect [ 62.69291
452.7736
@@ -316,10 +316,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 48 0 R
+ /Dest [ 50 0 R
/XYZ
62.69291
- 683.8236
+ 765.0236
0 ]
/Rect [ 527.0227
452.7736
@@ -334,10 +334,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 48 0 R
+ /Dest [ 50 0 R
/XYZ
62.69291
- 269.2236
+ 338.4236
0 ]
/Rect [ 62.69291
434.7736
@@ -352,10 +352,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 48 0 R
+ /Dest [ 50 0 R
/XYZ
62.69291
- 269.2236
+ 338.4236
0 ]
/Rect [ 527.0227
434.7736
@@ -370,10 +370,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 49 0 R
+ /Dest [ 51 0 R
/XYZ
62.69291
- 410.6236
+ 479.8236
0 ]
/Rect [ 62.69291
416.7736
@@ -388,10 +388,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 49 0 R
+ /Dest [ 51 0 R
/XYZ
62.69291
- 410.6236
+ 479.8236
0 ]
/Rect [ 527.0227
416.7736
@@ -406,14 +406,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 51 0 R
+ /Dest [ 53 0 R
/XYZ
62.69291
- 563.8236
+ 643.8236
0 ]
/Rect [ 62.69291
398.7736
- 192.2729
+ 139.9329
410.7736 ]
/Subtype /Link
/Type /Annot >>
@@ -424,10 +424,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 51 0 R
+ /Dest [ 53 0 R
/XYZ
62.69291
- 563.8236
+ 643.8236
0 ]
/Rect [ 527.0227
398.7736
@@ -442,14 +442,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 53 0 R
+ /Dest [ 54 0 R
/XYZ
62.69291
- 579.0236
+ 729.0236
0 ]
/Rect [ 62.69291
380.7736
- 177.1629
+ 192.2729
392.7736 ]
/Subtype /Link
/Type /Annot >>
@@ -460,10 +460,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 53 0 R
+ /Dest [ 54 0 R
/XYZ
62.69291
- 579.0236
+ 729.0236
0 ]
/Rect [ 521.4627
380.7736
@@ -478,14 +478,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 55 0 R
+ /Dest [ 56 0 R
/XYZ
62.69291
765.0236
0 ]
/Rect [ 62.69291
362.7736
- 228.2829
+ 177.1629
374.7736 ]
/Subtype /Link
/Type /Annot >>
@@ -496,7 +496,7 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 55 0 R
+ /Dest [ 56 0 R
/XYZ
62.69291
765.0236
@@ -517,11 +517,11 @@ endobj
/Dest [ 56 0 R
/XYZ
62.69291
- 371.0236
+ 318.4236
0 ]
/Rect [ 62.69291
344.7736
- 174.3929
+ 228.2829
356.7736 ]
/Subtype /Link
/Type /Annot >>
@@ -535,7 +535,7 @@ endobj
/Dest [ 56 0 R
/XYZ
62.69291
- 371.0236
+ 318.4236
0 ]
/Rect [ 521.4627
344.7736
@@ -550,14 +550,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 65 0 R
+ /Dest [ 59 0 R
/XYZ
62.69291
- 530.6236
+ 615.8236
0 ]
/Rect [ 62.69291
326.7736
- 155.4829
+ 174.3929
338.7736 ]
/Subtype /Link
/Type /Annot >>
@@ -568,10 +568,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 65 0 R
+ /Dest [ 59 0 R
/XYZ
62.69291
- 530.6236
+ 615.8236
0 ]
/Rect [ 521.4627
326.7736
@@ -586,14 +586,14 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 65 0 R
+ /Dest [ 68 0 R
/XYZ
62.69291
- 179.6236
+ 765.0236
0 ]
/Rect [ 62.69291
308.7736
- 106.5829
+ 155.4829
320.7736 ]
/Subtype /Link
/Type /Annot >>
@@ -604,10 +604,10 @@ endobj
0
0 ]
/Contents ()
- /Dest [ 65 0 R
+ /Dest [ 68 0 R
/XYZ
62.69291
- 179.6236
+ 765.0236
0 ]
/Rect [ 521.4627
308.7736
@@ -616,8 +616,44 @@ endobj
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page1': class PDFPage
+% 'Annot.NUMBER33': class LinkAnnotation
38 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 68 0 R
+ /XYZ
+ 62.69291
+ 414.0236
+ 0 ]
+ /Rect [ 62.69291
+ 290.7736
+ 106.5829
+ 302.7736 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Annot.NUMBER34': class LinkAnnotation
+39 0 obj
+<< /Border [ 0
+ 0
+ 0 ]
+ /Contents ()
+ /Dest [ 68 0 R
+ /XYZ
+ 62.69291
+ 414.0236
+ 0 ]
+ /Rect [ 521.4627
+ 290.7736
+ 532.5827
+ 302.7736 ]
+ /Subtype /Link
+ /Type /Annot >>
+endobj
+% 'Page1': class PDFPage
+40 0 obj
% Page dictionary
<< /Annots [ 5 0 R
6 0 R
@@ -650,13 +686,15 @@ endobj
34 0 R
35 0 R
36 0 R
- 37 0 R ]
- /Contents 86 0 R
+ 37 0 R
+ 38 0 R
+ 39 0 R ]
+ /Contents 89 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 85 0 R
+ /Parent 88 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -668,7 +706,7 @@ endobj
/Type /Page >>
endobj
% 'F5': class PDFType1Font
-39 0 obj
+41 0 obj
% Font Helvetica-Oblique
<< /BaseFont /Helvetica-Oblique
/Encoding /WinAnsiEncoding
@@ -676,8 +714,8 @@ endobj
/Subtype /Type1
/Type /Font >>
endobj
-% 'Annot.NUMBER33': class PDFDictionary
-40 0 obj
+% 'Annot.NUMBER35': class PDFDictionary
+42 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://www.python.org/moin/PythonDecoratorLibrary) >>
@@ -685,14 +723,14 @@ endobj
0
0 ]
/Rect [ 219.6428
- 363.7736
+ 345.7736
449.1728
- 375.7736 ]
+ 357.7736 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'F6': class PDFType1Font
-41 0 obj
+43 0 obj
% Font Courier-Oblique
<< /BaseFont /Courier-Oblique
/Encoding /WinAnsiEncoding
@@ -700,8 +738,8 @@ endobj
/Subtype /Type1
/Type /Font >>
endobj
-% 'Annot.NUMBER34': class PDFDictionary
-42 0 obj
+% 'Annot.NUMBER36': class PDFDictionary
+44 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://www.python.org/doc/2.5.2/lib/module-functools.html) >>
@@ -709,23 +747,23 @@ endobj
0
0 ]
/Rect [ 151.0486
- 130.5736
+ 112.5736
270.69
- 142.5736 ]
+ 124.5736 ]
/Subtype /Link
/Type /Annot >>
endobj
% 'Page2': class PDFPage
-43 0 obj
+45 0 obj
% Page dictionary
-<< /Annots [ 40 0 R
- 42 0 R ]
- /Contents 87 0 R
+<< /Annots [ 42 0 R
+ 44 0 R ]
+ /Contents 90 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 85 0 R
+ /Parent 88 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -737,14 +775,14 @@ endobj
/Type /Page >>
endobj
% 'Page3': class PDFPage
-44 0 obj
+46 0 obj
% Page dictionary
-<< /Contents 88 0 R
+<< /Contents 91 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 85 0 R
+ /Parent 88 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -756,14 +794,14 @@ endobj
/Type /Page >>
endobj
% 'Page4': class PDFPage
-45 0 obj
+47 0 obj
% Page dictionary
-<< /Contents 89 0 R
+<< /Contents 92 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 85 0 R
+ /Parent 88 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -774,8 +812,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER35': class PDFDictionary
-46 0 obj
+% 'Annot.NUMBER37': class PDFDictionary
+48 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://www.python.org/dev/peps/pep-3107/) >>
@@ -790,15 +828,15 @@ endobj
/Type /Annot >>
endobj
% 'Page5': class PDFPage
-47 0 obj
+49 0 obj
% Page dictionary
-<< /Annots [ 46 0 R ]
- /Contents 90 0 R
+<< /Annots [ 48 0 R ]
+ /Contents 93 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 85 0 R
+ /Parent 88 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -810,14 +848,14 @@ endobj
/Type /Page >>
endobj
% 'Page6': class PDFPage
-48 0 obj
+50 0 obj
% Page dictionary
-<< /Contents 91 0 R
+<< /Contents 94 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 85 0 R
+ /Parent 88 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -829,14 +867,14 @@ endobj
/Type /Page >>
endobj
% 'Page7': class PDFPage
-49 0 obj
+51 0 obj
% Page dictionary
-<< /Contents 92 0 R
+<< /Contents 95 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 85 0 R
+ /Parent 88 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -848,14 +886,14 @@ endobj
/Type /Page >>
endobj
% 'Page8': class PDFPage
-50 0 obj
+52 0 obj
% Page dictionary
-<< /Contents 93 0 R
+<< /Contents 96 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 85 0 R
+ /Parent 88 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -867,14 +905,14 @@ endobj
/Type /Page >>
endobj
% 'Page9': class PDFPage
-51 0 obj
+53 0 obj
% Page dictionary
-<< /Contents 94 0 R
+<< /Contents 97 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 85 0 R
+ /Parent 88 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -885,8 +923,27 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER36': class PDFDictionary
-52 0 obj
+% 'Page10': class PDFPage
+54 0 obj
+% Page dictionary
+<< /Contents 98 0 R
+ /MediaBox [ 0
+ 0
+ 595.2756
+ 841.8898 ]
+ /Parent 88 0 R
+ /Resources << /Font 1 0 R
+ /ProcSet [ /PDF
+ /Text
+ /ImageB
+ /ImageC
+ /ImageI ] >>
+ /Rotate 0
+ /Trans << >>
+ /Type /Page >>
+endobj
+% 'Annot.NUMBER38': class PDFDictionary
+55 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://bugs.python.org/issue1764286) >>
@@ -894,22 +951,22 @@ endobj
0
0 ]
/Rect [ 137.6966
- 286.3736
+ 472.3736
180.8679
- 298.3736 ]
+ 484.3736 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page10': class PDFPage
-53 0 obj
+% 'Page11': class PDFPage
+56 0 obj
% Page dictionary
-<< /Annots [ 52 0 R ]
- /Contents 95 0 R
+<< /Annots [ 55 0 R ]
+ /Contents 99 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 85 0 R
+ /Parent 88 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -920,8 +977,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER37': class PDFDictionary
-54 0 obj
+% 'Annot.NUMBER39': class PDFDictionary
+57 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496691) >>
@@ -929,22 +986,22 @@ endobj
0
0 ]
/Rect [ 62.69291
- 445.5736
+ 675.7736
363.4029
- 457.5736 ]
+ 687.7736 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page11': class PDFPage
-55 0 obj
+% 'Page12': class PDFPage
+58 0 obj
% Page dictionary
-<< /Annots [ 54 0 R ]
- /Contents 96 0 R
+<< /Annots [ 57 0 R ]
+ /Contents 100 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 85 0 R
+ /Parent 88 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -955,15 +1012,15 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Page12': class PDFPage
-56 0 obj
+% 'Page13': class PDFPage
+59 0 obj
% Page dictionary
-<< /Contents 97 0 R
+<< /Contents 101 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 85 0 R
+ /Parent 88 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -974,8 +1031,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER38': class PDFDictionary
-57 0 obj
+% 'Annot.NUMBER40': class PDFDictionary
+60 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://www.python.org/dev/peps/pep-0362) >>
@@ -983,22 +1040,22 @@ endobj
0
0 ]
/Rect [ 301.1597
- 282.1736
+ 534.5736
317.8397
- 294.1736 ]
+ 546.5736 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page13': class PDFPage
-58 0 obj
+% 'Page14': class PDFPage
+61 0 obj
% Page dictionary
-<< /Annots [ 57 0 R ]
- /Contents 98 0 R
+<< /Annots [ 60 0 R ]
+ /Contents 102 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 85 0 R
+ /Parent 88 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1009,8 +1066,8 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'Annot.NUMBER39': class PDFDictionary
-59 0 obj
+% 'Annot.NUMBER41': class PDFDictionary
+62 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://www.python.org/dev/peps/pep-3107/) >>
@@ -1018,14 +1075,14 @@ endobj
0
0 ]
/Rect [ 497.5627
- 492.3736
+ 726.7736
531.1777
- 504.3736 ]
+ 738.7736 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER40': class PDFDictionary
-60 0 obj
+% 'Annot.NUMBER42': class PDFDictionary
+63 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://www.python.org/dev/peps/pep-3107/) >>
@@ -1033,14 +1090,14 @@ endobj
0
0 ]
/Rect [ 62.69291
- 480.3736
+ 714.7736
114.3929
- 492.3736 ]
+ 726.7736 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER41': class PDFDictionary
-61 0 obj
+% 'Annot.NUMBER43': class PDFDictionary
+64 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://packages.python.org/distribute/) >>
@@ -1048,14 +1105,14 @@ endobj
0
0 ]
/Rect [ 172.9507
- 468.3736
+ 702.7736
216.6742
- 480.3736 ]
+ 714.7736 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER42': class PDFDictionary
-62 0 obj
+% 'Annot.NUMBER44': class PDFDictionary
+65 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://docutils.sourceforge.net/) >>
@@ -1063,14 +1120,14 @@ endobj
0
0 ]
/Rect [ 82.15291
- 444.3736
+ 678.7736
118.8329
- 456.3736 ]
+ 690.7736 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER43': class PDFDictionary
-63 0 obj
+% 'Annot.NUMBER45': class PDFDictionary
+66 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://pygments.org/) >>
@@ -1078,14 +1135,14 @@ endobj
0
0 ]
/Rect [ 138.2929
- 444.3736
+ 678.7736
184.4229
- 456.3736 ]
+ 690.7736 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Annot.NUMBER44': class PDFDictionary
-64 0 obj
+% 'Annot.NUMBER46': class PDFDictionary
+67 0 obj
<< /A << /S /URI
/Type /Action
/URI (http://www.phyast.pitt.edu/~micheles/python/documentation.html#class-decorators-and-decorator-factories) >>
@@ -1093,46 +1150,27 @@ endobj
0
0 ]
/Rect [ 364.2921
- 306.3736
+ 540.7736
531.64
- 318.3736 ]
+ 552.7736 ]
/Subtype /Link
/Type /Annot >>
endobj
-% 'Page14': class PDFPage
-65 0 obj
-% Page dictionary
-<< /Annots [ 59 0 R
- 60 0 R
- 61 0 R
- 62 0 R
- 63 0 R
- 64 0 R ]
- /Contents 99 0 R
- /MediaBox [ 0
- 0
- 595.2756
- 841.8898 ]
- /Parent 85 0 R
- /Resources << /Font 1 0 R
- /ProcSet [ /PDF
- /Text
- /ImageB
- /ImageC
- /ImageI ] >>
- /Rotate 0
- /Trans << >>
- /Type /Page >>
-endobj
% 'Page15': class PDFPage
-66 0 obj
+68 0 obj
% Page dictionary
-<< /Contents 100 0 R
+<< /Annots [ 62 0 R
+ 63 0 R
+ 64 0 R
+ 65 0 R
+ 66 0 R
+ 67 0 R ]
+ /Contents 103 0 R
/MediaBox [ 0
0
595.2756
841.8898 ]
- /Parent 85 0 R
+ /Parent 88 0 R
/Resources << /Font 1 0 R
/ProcSet [ /PDF
/Text
@@ -1143,235 +1181,247 @@ endobj
/Trans << >>
/Type /Page >>
endobj
-% 'R67': class PDFCatalog
-67 0 obj
+% 'R69': class PDFCatalog
+69 0 obj
% Document Root
-<< /Outlines 69 0 R
- /PageLabels 101 0 R
+<< /Outlines 71 0 R
+ /PageLabels 104 0 R
/PageMode /UseNone
- /Pages 85 0 R
+ /Pages 88 0 R
/Type /Catalog >>
endobj
-% 'R68': class PDFInfo
-68 0 obj
+% 'R70': class PDFInfo
+70 0 obj
<< /Author (Michele Simionato)
- /CreationDate (D:20111109152300-01'00')
+ /CreationDate (D:20121018102601-01'00')
/Creator (\(unspecified\))
/Keywords ()
/Producer (ReportLab PDF Library - www.reportlab.com)
/Subject (\(unspecified\))
/Title (The decorator module) >>
endobj
-% 'R69': class PDFOutlines
-69 0 obj
-<< /Count 15
- /First 70 0 R
- /Last 84 0 R
+% 'R71': class PDFOutlines
+71 0 obj
+<< /Count 16
+ /First 72 0 R
+ /Last 87 0 R
/Type /Outlines >>
endobj
% 'Outline.0': class OutlineEntryObject
-70 0 obj
-<< /Dest [ 38 0 R
- /XYZ
- 62.69291
- 293.0236
- 0 ]
- /Next 71 0 R
- /Parent 69 0 R
- /Title (Introduction) >>
-endobj
-% 'Outline.1': class OutlineEntryObject
-71 0 obj
-<< /Dest [ 43 0 R
- /XYZ
- 62.69291
- 675.0236
- 0 ]
- /Next 72 0 R
- /Parent 69 0 R
- /Prev 70 0 R
- /Title (Definitions) >>
-endobj
-% 'Outline.2': class OutlineEntryObject
72 0 obj
-<< /Dest [ 43 0 R
+<< /Dest [ 40 0 R
/XYZ
62.69291
- 438.0236
+ 275.0236
0 ]
/Next 73 0 R
- /Parent 69 0 R
- /Prev 71 0 R
- /Title (Statement of the problem) >>
+ /Parent 71 0 R
+ /Title (Introduction) >>
endobj
-% 'Outline.3': class OutlineEntryObject
+% 'Outline.1': class OutlineEntryObject
73 0 obj
-<< /Dest [ 44 0 R
+<< /Dest [ 45 0 R
/XYZ
62.69291
- 427.4236
+ 657.0236
0 ]
/Next 74 0 R
- /Parent 69 0 R
+ /Parent 71 0 R
/Prev 72 0 R
- /Title (The solution) >>
+ /Title (Definitions) >>
endobj
-% 'Outline.4': class OutlineEntryObject
+% 'Outline.2': class OutlineEntryObject
74 0 obj
<< /Dest [ 45 0 R
/XYZ
62.69291
- 435.4236
+ 420.0236
0 ]
/Next 75 0 R
- /Parent 69 0 R
+ /Parent 71 0 R
/Prev 73 0 R
- /Title (A trace decorator) >>
+ /Title (Statement of the problem) >>
endobj
-% 'Outline.5': class OutlineEntryObject
+% 'Outline.3': class OutlineEntryObject
75 0 obj
-<< /Dest [ 47 0 R
+<< /Dest [ 46 0 R
/XYZ
62.69291
- 567.978
+ 409.4236
0 ]
/Next 76 0 R
- /Parent 69 0 R
+ /Parent 71 0 R
/Prev 74 0 R
- /Title (Function annotations) >>
+ /Title (The solution) >>
endobj
-% 'Outline.6': class OutlineEntryObject
+% 'Outline.4': class OutlineEntryObject
76 0 obj
-<< /Dest [ 48 0 R
+<< /Dest [ 47 0 R
/XYZ
62.69291
- 683.8236
+ 435.4236
0 ]
/Next 77 0 R
- /Parent 69 0 R
+ /Parent 71 0 R
/Prev 75 0 R
- /Title (decorator is a decorator) >>
+ /Title (A trace decorator) >>
endobj
-% 'Outline.7': class OutlineEntryObject
+% 'Outline.5': class OutlineEntryObject
77 0 obj
-<< /Dest [ 48 0 R
+<< /Dest [ 49 0 R
/XYZ
62.69291
- 269.2236
+ 567.978
0 ]
/Next 78 0 R
- /Parent 69 0 R
+ /Parent 71 0 R
/Prev 76 0 R
- /Title (blocking) >>
+ /Title (Function annotations) >>
endobj
-% 'Outline.8': class OutlineEntryObject
+% 'Outline.6': class OutlineEntryObject
78 0 obj
-<< /Dest [ 49 0 R
+<< /Dest [ 50 0 R
/XYZ
62.69291
- 410.6236
+ 765.0236
0 ]
/Next 79 0 R
- /Parent 69 0 R
+ /Parent 71 0 R
/Prev 77 0 R
- /Title (async) >>
+ /Title (decorator is a decorator) >>
endobj
-% 'Outline.9': class OutlineEntryObject
+% 'Outline.7': class OutlineEntryObject
79 0 obj
-<< /Dest [ 51 0 R
+<< /Dest [ 50 0 R
/XYZ
62.69291
- 563.8236
+ 338.4236
0 ]
/Next 80 0 R
- /Parent 69 0 R
+ /Parent 71 0 R
/Prev 78 0 R
- /Title (The FunctionMaker class) >>
+ /Title (blocking) >>
endobj
-% 'Outline.10': class OutlineEntryObject
+% 'Outline.8': class OutlineEntryObject
80 0 obj
-<< /Dest [ 53 0 R
+<< /Dest [ 51 0 R
/XYZ
62.69291
- 579.0236
+ 479.8236
0 ]
/Next 81 0 R
- /Parent 69 0 R
+ /Parent 71 0 R
/Prev 79 0 R
- /Title (Getting the source code) >>
+ /Title (async) >>
endobj
-% 'Outline.11': class OutlineEntryObject
+% 'Outline.9': class OutlineEntryObject
81 0 obj
-<< /Dest [ 55 0 R
+<< /Dest [ 53 0 R
/XYZ
62.69291
- 765.0236
+ 643.8236
0 ]
/Next 82 0 R
- /Parent 69 0 R
+ /Parent 71 0 R
/Prev 80 0 R
- /Title (Dealing with third party decorators) >>
+ /Title (contextmanager) >>
endobj
-% 'Outline.12': class OutlineEntryObject
+% 'Outline.10': class OutlineEntryObject
82 0 obj
-<< /Dest [ 56 0 R
+<< /Dest [ 54 0 R
/XYZ
62.69291
- 371.0236
+ 729.0236
0 ]
/Next 83 0 R
- /Parent 69 0 R
+ /Parent 71 0 R
/Prev 81 0 R
- /Title (Caveats and limitations) >>
+ /Title (The FunctionMaker class) >>
endobj
-% 'Outline.13': class OutlineEntryObject
+% 'Outline.11': class OutlineEntryObject
83 0 obj
-<< /Dest [ 65 0 R
+<< /Dest [ 56 0 R
/XYZ
62.69291
- 530.6236
+ 765.0236
0 ]
/Next 84 0 R
- /Parent 69 0 R
+ /Parent 71 0 R
/Prev 82 0 R
- /Title (Compatibility notes) >>
+ /Title (Getting the source code) >>
endobj
-% 'Outline.14': class OutlineEntryObject
+% 'Outline.12': class OutlineEntryObject
84 0 obj
-<< /Dest [ 65 0 R
+<< /Dest [ 56 0 R
/XYZ
62.69291
- 179.6236
+ 318.4236
0 ]
- /Parent 69 0 R
+ /Next 85 0 R
+ /Parent 71 0 R
/Prev 83 0 R
- /Title (LICENCE) >>
+ /Title (Dealing with third party decorators) >>
endobj
-% 'R85': class PDFPages
+% 'Outline.13': class OutlineEntryObject
85 0 obj
+<< /Dest [ 59 0 R
+ /XYZ
+ 62.69291
+ 615.8236
+ 0 ]
+ /Next 86 0 R
+ /Parent 71 0 R
+ /Prev 84 0 R
+ /Title (Caveats and limitations) >>
+endobj
+% 'Outline.14': class OutlineEntryObject
+86 0 obj
+<< /Dest [ 68 0 R
+ /XYZ
+ 62.69291
+ 765.0236
+ 0 ]
+ /Next 87 0 R
+ /Parent 71 0 R
+ /Prev 85 0 R
+ /Title (Compatibility notes) >>
+endobj
+% 'Outline.15': class OutlineEntryObject
+87 0 obj
+<< /Dest [ 68 0 R
+ /XYZ
+ 62.69291
+ 414.0236
+ 0 ]
+ /Parent 71 0 R
+ /Prev 86 0 R
+ /Title (LICENCE) >>
+endobj
+% 'R88': class PDFPages
+88 0 obj
% page tree
<< /Count 15
- /Kids [ 38 0 R
- 43 0 R
- 44 0 R
+ /Kids [ 40 0 R
45 0 R
+ 46 0 R
47 0 R
- 48 0 R
49 0 R
50 0 R
51 0 R
+ 52 0 R
53 0 R
- 55 0 R
+ 54 0 R
56 0 R
58 0 R
- 65 0 R
- 66 0 R ]
+ 59 0 R
+ 61 0 R
+ 68 0 R ]
/Type /Pages >>
endobj
-% 'R86': class PDFStream
-86 0 obj
+% 'R89': class PDFStream
+89 0 obj
% page stream
-<< /Length 9041 >>
+<< /Length 9258 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -1436,7 +1486,7 @@ 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 (3.3.2 \(2011-11-09\)) Tj T* ET
+BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (3.4.0 \(2012-10-18\)) Tj T* ET
Q
Q
q
@@ -1479,7 +1529,7 @@ q
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/3.3.2) Tj T* ET
+BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (http://pypi.python.org/pypi/decorator/3.4.0) Tj T* ET
Q
Q
q
@@ -1499,8 +1549,7 @@ Q
q
1 0 0 1 91.03937 3 cm
q
-0 0 0 rg
-BT 1 0 0 1 0 2 Tm /F4 10 Tf 12 TL (easy_install decorator) Tj T* ET
+BT 1 0 0 1 0 2 Tm 12 TL /F4 10 Tf 0 0 0 rg (easy_install) Tj ( ) Tj (decorator) Tj T* ET
Q
Q
q
@@ -1534,17 +1583,17 @@ 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 305.0236 cm
+1 0 0 1 62.69291 287.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
-1 0 0 1 0 255 cm
+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 (Introduction) Tj T* ET
Q
Q
q
-1 0 0 1 397.8898 255 cm
+1 0 0 1 397.8898 273 cm
q
0 0 .501961 rg
0 0 .501961 RG
@@ -1552,12 +1601,26 @@ BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (1) Tj T* -66.44 0 Td ET
Q
Q
q
-1 0 0 1 0 237 cm
+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 (Definitions) 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 (2) 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 (Statement of the problem) Tj T* ET
+Q
+Q
+q
1 0 0 1 397.8898 237 cm
q
0 0 .501961 rg
@@ -1568,7 +1631,7 @@ 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 (Statement of the problem) Tj T* ET
+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
@@ -1576,13 +1639,13 @@ q
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
+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 201 cm
q
-BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (The solution) Tj T* ET
+BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (A ) Tj /F3 10 Tf (trace ) Tj /F2 10 Tf (decorator) Tj T* ET
Q
Q
q
@@ -1590,13 +1653,13 @@ q
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
+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 183 cm
q
-BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (A ) Tj /F3 10 Tf (trace ) Tj /F2 10 Tf (decorator) Tj T* ET
+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
@@ -1604,13 +1667,13 @@ q
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
+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 165 cm
q
-BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Function annotations) Tj T* ET
+BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 .501961 rg (decorator ) Tj /F2 10 Tf (is a decorator) Tj T* ET
Q
Q
q
@@ -1618,13 +1681,13 @@ q
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
+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 147 cm
q
-BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 .501961 rg (decorator ) Tj /F2 10 Tf (is a decorator) Tj T* ET
+BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 .501961 rg (blocking) Tj T* ET
Q
Q
q
@@ -1638,7 +1701,7 @@ Q
q
1 0 0 1 0 129 cm
q
-BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 .501961 rg (blocking) Tj T* ET
+BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 .501961 rg (async) Tj T* ET
Q
Q
q
@@ -1646,13 +1709,13 @@ q
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
+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 111 cm
q
-BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 .501961 rg (async) Tj T* ET
+BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (contextmanager) Tj T* ET
Q
Q
q
@@ -1660,7 +1723,7 @@ q
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
+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
@@ -1674,7 +1737,7 @@ q
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
+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
@@ -1688,7 +1751,7 @@ q
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
+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
@@ -1716,7 +1779,7 @@ q
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
+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
@@ -1730,7 +1793,7 @@ q
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 (14) Tj T* -60.88 0 Td ET
+BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 60.88 0 Td (15) Tj T* -60.88 0 Td ET
Q
Q
q
@@ -1744,33 +1807,33 @@ q
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 (14) Tj T* -60.88 0 Td ET
+BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 60.88 0 Td (15) Tj T* -60.88 0 Td ET
Q
Q
q
Q
Q
q
-1 0 0 1 62.69291 272.0236 cm
+1 0 0 1 62.69291 254.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 206.0236 cm
+1 0 0 1 62.69291 188.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 200.0236 cm
+1 0 0 1 62.69291 182.0236 cm
Q
q
-1 0 0 1 62.69291 200.0236 cm
+1 0 0 1 62.69291 182.0236 cm
Q
q
-1 0 0 1 62.69291 188.0236 cm
+1 0 0 1 62.69291 170.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -1791,10 +1854,10 @@ q
Q
Q
q
-1 0 0 1 62.69291 182.0236 cm
+1 0 0 1 62.69291 164.0236 cm
Q
q
-1 0 0 1 62.69291 170.0236 cm
+1 0 0 1 62.69291 152.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -1815,10 +1878,10 @@ q
Q
Q
q
-1 0 0 1 62.69291 164.0236 cm
+1 0 0 1 62.69291 146.0236 cm
Q
q
-1 0 0 1 62.69291 152.0236 cm
+1 0 0 1 62.69291 134.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -1839,10 +1902,10 @@ q
Q
Q
q
-1 0 0 1 62.69291 146.0236 cm
+1 0 0 1 62.69291 128.0236 cm
Q
q
-1 0 0 1 62.69291 134.0236 cm
+1 0 0 1 62.69291 116.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -1863,57 +1926,64 @@ q
Q
Q
q
-1 0 0 1 62.69291 134.0236 cm
+1 0 0 1 62.69291 116.0236 cm
Q
q
-1 0 0 1 62.69291 92.02362 cm
+1 0 0 1 62.69291 86.02362 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
+BT 1 0 0 1 0 14 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 ET
Q
Q
endstream
endobj
-% 'R87': class PDFStream
-87 0 obj
+% 'R90': class PDFStream
+90 0 obj
% page stream
-<< /Length 7546 >>
+<< /Length 7660 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 717.0236 cm
+1 0 0 1 62.69291 753.0236 cm
+q
+0 0 0 rg
+BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (that flat is better than nested.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 699.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 /F4 10 Tf (decorator ) Tj /F1 10 Tf (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
q
-1 0 0 1 62.69291 687.0236 cm
+1 0 0 1 62.69291 669.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 /F4 10 Tf (documentation.py ) Tj /F1 10 Tf (file, which) Tj T* 0 Tw (contains this documentation in the form of doctests.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 654.0236 cm
+1 0 0 1 62.69291 636.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 612.0236 cm
+1 0 0 1 62.69291 594.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 606.0236 cm
+1 0 0 1 62.69291 588.0236 cm
Q
q
-1 0 0 1 62.69291 606.0236 cm
+1 0 0 1 62.69291 588.0236 cm
Q
q
-1 0 0 1 62.69291 582.0236 cm
+1 0 0 1 62.69291 564.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -1933,10 +2003,10 @@ q
Q
Q
q
-1 0 0 1 62.69291 576.0236 cm
+1 0 0 1 62.69291 558.0236 cm
Q
q
-1 0 0 1 62.69291 552.0236 cm
+1 0 0 1 62.69291 534.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
q
@@ -1956,42 +2026,42 @@ q
Q
Q
q
-1 0 0 1 62.69291 552.0236 cm
+1 0 0 1 62.69291 534.0236 cm
Q
q
-1 0 0 1 62.69291 510.0236 cm
+1 0 0 1 62.69291 492.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 /F4 10 Tf (staticmethod ) Tj /F1 10 Tf (and) Tj T* 0 Tw 1.506651 Tw /F4 10 Tf (classmethod ) Tj /F1 10 Tf (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 480.0236 cm
+1 0 0 1 62.69291 462.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 450.0236 cm
+1 0 0 1 62.69291 432.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 417.0236 cm
+1 0 0 1 62.69291 399.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 339.0236 cm
+1 0 0 1 62.69291 321.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 /F4 10 Tf (memoize ) Tj /F1 10 Tf (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 /F4 10 Tf (memoize ) Tj /F1 10 Tf (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 2.683984 Tw (preserve the signature. A simple implementation could be the following \(notice that in general it is) Tj T* 0 Tw (impossible to memoize correctly something that depends on non-hashable arguments\):) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 149.8236 cm
+1 0 0 1 62.69291 131.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -2011,35 +2081,42 @@ Q
Q
Q
q
-1 0 0 1 62.69291 93.82362 cm
+1 0 0 1 62.69291 87.82362 cm
q
-BT 1 0 0 1 0 38 Tm 1.801412 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here we 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 /F4 10 Tf (__name__) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (__doc__) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (__module__ ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (__dict__ ) Tj /F1 10 Tf (from the original function to the decorated function) Tj T* 0 Tw (by hand\).) Tj T* ET
+BT 1 0 0 1 0 26 Tm 1.801412 Tw 12 TL /F1 10 Tf 0 0 0 rg (Here we 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 /F4 10 Tf (__name__) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (__doc__) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (__module__ ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (__dict__ ) Tj /F1 10 Tf (from the original function to the decorated function) Tj T* 0 Tw ET
Q
Q
endstream
endobj
-% 'R88': class PDFStream
-88 0 obj
+% 'R91': class PDFStream
+91 0 obj
% page stream
-<< /Length 7967 >>
+<< /Length 8095 >>
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
+1 0 0 1 62.69291 753.0236 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 /F5 10 Tf (not ) Tj /F1 10 Tf (define a signature-preserving decorator, since in) Tj T* 0 Tw (general ) Tj /F4 10 Tf (memoize_uw ) Tj /F1 10 Tf (returns a function with a ) Tj /F5 10 Tf (different signature ) Tj /F1 10 Tf (from the original function.) Tj T* ET
+0 0 0 rg
+BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (by hand\).) Tj T* ET
Q
Q
q
1 0 0 1 62.69291 711.0236 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 /F5 10 Tf (not ) Tj /F1 10 Tf (define a signature-preserving decorator, since in) Tj T* 0 Tw (general ) Tj /F4 10 Tf (memoize_uw ) Tj /F1 10 Tf (returns a function with a ) Tj /F5 10 Tf (different signature ) Tj /F1 10 Tf (from the original function.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 693.0236 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 641.8236 cm
+1 0 0 1 62.69291 623.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -2059,13 +2136,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 609.8236 cm
+1 0 0 1 62.69291 591.8236 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 /F4 10 Tf (x) Tj /F1 10 Tf (, 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 552.6236 cm
+1 0 0 1 62.69291 534.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -2085,13 +2162,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 508.6236 cm
+1 0 0 1 62.69291 490.6236 cm
q
BT 1 0 0 1 0 26 Tm .411235 Tw 12 TL /F1 10 Tf 0 0 0 rg (This means that introspection tools such as pydoc will give wrong informations about the signature of ) Tj /F4 10 Tf (f1) Tj /F1 10 Tf (.) Tj T* 0 Tw .161654 Tw (This is pretty bad: pydoc will tell you that the function accepts a generic signature ) Tj /F4 10 Tf (*args) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (**kw) Tj /F1 10 Tf (, but when) Tj T* 0 Tw (you try to call the function with more than an argument, you will get an error:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 439.4236 cm
+1 0 0 1 62.69291 421.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -2111,19 +2188,19 @@ Q
Q
Q
q
-1 0 0 1 62.69291 406.4236 cm
+1 0 0 1 62.69291 388.4236 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 364.4236 cm
+1 0 0 1 62.69291 346.4236 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.362976 Tw (signature-preserving decorators from the application programmer. The ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (function in the) Tj T* 0 Tw /F4 10 Tf (decorator ) Tj /F1 10 Tf (module is such a factory:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 331.2236 cm
+1 0 0 1 62.69291 313.2236 cm
q
q
1 0 0 1 0 0 cm
@@ -2143,13 +2220,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 275.2236 cm
+1 0 0 1 62.69291 257.2236 cm
q
-BT 1 0 0 1 0 38 Tm 1.716412 Tw 12 TL /F4 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf (takes two arguments, a caller function describing the functionality of the decorator and a) Tj T* 0 Tw .821984 Tw (function to be decorated; it returns the decorated function. The caller function must have signature ) Tj /F4 10 Tf (\(f,) Tj T* 0 Tw .65061 Tw (*args, **kw\) ) Tj /F1 10 Tf (and it must call the original function ) Tj /F4 10 Tf (f ) Tj /F1 10 Tf (with arguments ) Tj /F4 10 Tf (args ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (kw) Tj /F1 10 Tf (, implementing the) Tj T* 0 Tw (wanted capability, i.e. memoization in this case:) Tj T* ET
+BT 1 0 0 1 0 38 Tm 1.716412 Tw 12 TL /F4 10 Tf 0 0 0 rg (decorator ) Tj /F1 10 Tf (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 /F4 10 Tf (\(f,) Tj ( ) Tj (*args,) Tj ( ) Tj (**kw\) ) Tj /F1 10 Tf (and it must call the original function ) Tj /F4 10 Tf (f ) Tj /F1 10 Tf (with arguments ) Tj /F4 10 Tf (args ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (kw) Tj /F1 10 Tf (, 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 122.0236 cm
+1 0 0 1 62.69291 104.0236 cm
q
q
1 0 0 1 0 0 cm
@@ -2169,7 +2246,7 @@ Q
Q
Q
q
-1 0 0 1 62.69291 102.0236 cm
+1 0 0 1 62.69291 84.02362 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
@@ -2178,10 +2255,10 @@ Q
endstream
endobj
-% 'R89': class PDFStream
-89 0 obj
+% 'R92': class PDFStream
+92 0 obj
% page stream
-<< /Length 7127 >>
+<< /Length 7804 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -2276,7 +2353,7 @@ BT 1 0 0 1 0 14 Tm .479398 Tw 12 TL /F1 10 Tf 0 0 0 rg (As an additional example
Q
Q
q
-1 0 0 1 62.69291 327.2236 cm
+1 0 0 1 62.69291 315.2236 cm
q
q
1 0 0 1 0 0 cm
@@ -2286,17 +2363,17 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 48 re B*
+n -6 -6 468.6898 60 re B*
Q
q
-BT 1 0 0 1 0 26 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (_trace) Tj 0 0 0 rg (\() Tj (f) Tj (,) Tj ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (print) Tj /F4 10 Tf 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ("calling ) Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg ( with args ) Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg (, ) Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg (") Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (%) Tj 0 0 0 rg ( ) Tj (\() Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__name__) Tj (,) Tj ( ) Tj (args) Tj (,) Tj ( ) Tj (kw) Tj (\)\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (f) Tj (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\)) Tj T* ET
+BT 1 0 0 1 0 38 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (_trace) Tj 0 0 0 rg (\() Tj (f) Tj (,) Tj ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\):) Tj T* ( ) Tj (kwstr) Tj ( ) 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 (\() Tj .729412 .129412 .129412 rg (') Tj /F3 10 Tf .733333 .4 .533333 rg (%r) Tj /F4 10 Tf .729412 .129412 .129412 rg (: ) Tj /F3 10 Tf .733333 .4 .533333 rg (%r) Tj /F4 10 Tf .729412 .129412 .129412 rg (') Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (%) Tj 0 0 0 rg ( ) Tj (\() Tj (k) Tj (,) Tj ( ) Tj (kw) Tj ([) Tj (k) Tj (]\)) Tj ( ) Tj /F3 10 Tf 0 .501961 0 rg (for) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (k) Tj ( ) Tj /F3 10 Tf .666667 .133333 1 rg (in) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (sorted) Tj 0 0 0 rg (\() Tj (kw) Tj (\)\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (print) Tj /F4 10 Tf 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ("calling ) Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg ( with args ) Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg (, {) Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg (}") Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (%) Tj 0 0 0 rg ( ) Tj (\() Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__name__) Tj (,) Tj ( ) Tj (args) Tj (,) Tj ( ) Tj (kwstr) Tj (\)\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (f) Tj (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\)) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 282.0236 cm
+1 0 0 1 62.69291 270.0236 cm
q
q
1 0 0 1 0 0 cm
@@ -2316,14 +2393,14 @@ Q
Q
Q
q
-1 0 0 1 62.69291 262.0236 cm
+1 0 0 1 62.69291 250.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 204.8236 cm
+1 0 0 1 62.69291 192.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -2343,13 +2420,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 184.8236 cm
+1 0 0 1 62.69291 172.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 /F4 10 Tf (f1 ) Tj /F1 10 Tf (works) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 139.6236 cm
+1 0 0 1 62.69291 127.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -2369,7 +2446,7 @@ Q
Q
Q
q
-1 0 0 1 62.69291 119.6236 cm
+1 0 0 1 62.69291 107.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
@@ -2378,10 +2455,10 @@ Q
endstream
endobj
-% 'R90': class PDFStream
-90 0 obj
+% 'R93': class PDFStream
+93 0 obj
% page stream
-<< /Length 8189 >>
+<< /Length 7590 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
@@ -2470,7 +2547,7 @@ BT 1 0 0 1 0 14 Tm .596647 Tw 12 TL /F1 10 Tf 0 0 0 rg (In order to introspect f
Q
Q
q
-1 0 0 1 62.69291 178.578 cm
+1 0 0 1 62.69291 214.578 cm
q
q
1 0 0 1 0 0 cm
@@ -2480,23 +2557,23 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 204 re B*
+n -6 -6 468.6898 168 re B*
Q
q
-BT 1 0 0 1 0 182 Tm 12 TL /F4 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (from) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf 0 0 1 rg (inspect) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (import) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (getfullargspec) Tj T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (argspec) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (getfullargspec) Tj (\() Tj (f) Tj (\)) Tj T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (argspec) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (args) Tj T* ([) Tj .729412 .129412 .129412 rg ('x') Tj 0 0 0 rg (,) Tj ( ) Tj .729412 .129412 .129412 rg ('y') Tj 0 0 0 rg (,) Tj ( ) Tj .729412 .129412 .129412 rg ('z') Tj 0 0 0 rg (]) Tj T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (argspec) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (varargs) Tj T* .729412 .129412 .129412 rg ('args') Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (argspec) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (varkw) Tj T* .729412 .129412 .129412 rg ('kw') Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (argspec) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (defaults) Tj T* (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (,) Tj ( ) Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (\)) Tj T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (argspec) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (kwonlyargs) Tj T* ([]) Tj T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (argspec) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (kwonlydefaults) Tj T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (sorted) Tj 0 0 0 rg (\() Tj (argspec) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (annotations) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (items) Tj (\(\)\)) Tj T* ([\() Tj .729412 .129412 .129412 rg ('args') Tj 0 0 0 rg (,) Tj ( ) Tj .729412 .129412 .129412 rg ('varargs') Tj 0 0 0 rg (\),) Tj ( ) Tj (\() Tj .729412 .129412 .129412 rg ('kw') Tj 0 0 0 rg (,) Tj ( ) Tj .729412 .129412 .129412 rg ('kwargs') Tj 0 0 0 rg (\),) Tj ( ) Tj (\() Tj .729412 .129412 .129412 rg ('x') Tj 0 0 0 rg (,) Tj ( ) Tj .729412 .129412 .129412 rg ('the first argument') Tj 0 0 0 rg (\),) Tj ( ) Tj (\() Tj .729412 .129412 .129412 rg ('y') Tj 0 0 0 rg (,) Tj T* .729412 .129412 .129412 rg ('default argument') Tj 0 0 0 rg (\)]) Tj T* ET
+BT 1 0 0 1 0 146 Tm 12 TL /F4 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (from) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf 0 0 1 rg (inspect) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (import) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (getfullargspec) Tj T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (argspec) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (getfullargspec) Tj (\() Tj (f) Tj (\)) Tj T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (argspec) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (args) Tj T* ([) Tj .729412 .129412 .129412 rg ('x') Tj 0 0 0 rg (,) Tj ( ) Tj .729412 .129412 .129412 rg ('y') Tj 0 0 0 rg (,) Tj ( ) Tj .729412 .129412 .129412 rg ('z') Tj 0 0 0 rg (]) Tj T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (argspec) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (varargs) Tj T* .729412 .129412 .129412 rg ('args') Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (argspec) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (varkw) Tj T* .729412 .129412 .129412 rg ('kw') Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (argspec) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (defaults) Tj T* (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (,) Tj ( ) Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (\)) Tj T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (argspec) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (kwonlyargs) Tj T* ([]) Tj T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (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 158.578 cm
+1 0 0 1 62.69291 194.578 cm
q
BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (You can also check that the ) Tj /F4 10 Tf (__annotations__ ) Tj /F1 10 Tf (dictionary is preserved:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 113.378 cm
+1 0 0 1 62.69291 149.378 cm
q
q
1 0 0 1 0 0 cm
@@ -2516,61 +2593,35 @@ Q
Q
Q
q
-1 0 0 1 62.69291 93.378 cm
+1 0 0 1 62.69291 117.378 cm
q
0 0 0 rg
-BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (The two dictionaries are different objects, though) Tj T* ET
+BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .011098 Tw (Depending on the version of the decorator module, the two dictionaries can be the same object or not: you) Tj T* 0 Tw (cannot rely on object identity, but you can rely on the content being the same.) Tj T* ET
Q
Q
endstream
endobj
-% 'R91': class PDFStream
-91 0 obj
+% 'R94': class PDFStream
+94 0 obj
% page stream
-<< /Length 8363 >>
+<< /Length 8795 >>
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
-BT 1 0 0 1 0 14 Tm 12 TL /F4 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (id) Tj 0 0 0 rg (\() Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__annotations__) Tj (\)) Tj ( ) Tj .4 .4 .4 rg (!=) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (id) Tj 0 0 0 rg (\() Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__wrapped__) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__annotations__) Tj (\)) Tj T* 0 .501961 0 rg (True) 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 14 Tm 1.758651 Tw 12 TL /F1 10 Tf 0 0 0 rg (since internally the decorator module creates an entirely new dictionary \(it is not simply attaching the) Tj T* 0 Tw /F4 10 Tf (__annotations__ ) Tj /F1 10 Tf (attribute to the new function\).) Tj T* ET
-Q
-Q
-q
-1 0 0 1 62.69291 662.8236 cm
+1 0 0 1 62.69291 744.0236 cm
q
BT 1 0 0 1 0 3.5 Tm 21 TL /F3 17.5 Tf 0 0 0 rg (decorator ) Tj /F2 17.5 Tf (is a decorator) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 560.8236 cm
+1 0 0 1 62.69291 642.0236 cm
q
-BT 1 0 0 1 0 86 Tm .643876 Tw 12 TL /F1 10 Tf 0 0 0 rg (It may be annoying to write a caller function \(like the ) Tj /F4 10 Tf (_trace ) Tj /F1 10 Tf (function above\) and then a trivial wrapper) Tj T* 0 Tw 1.803615 Tw (\() Tj /F4 10 Tf (def trace\(f\): return decorator\(_trace, f\)) Tj /F1 10 Tf (\) every time. For this reason, the ) Tj /F4 10 Tf (decorator) Tj T* 0 Tw .334269 Tw /F1 10 Tf (module provides an easy shortcut to convert the caller function into a signature-preserving decorator: you) Tj T* 0 Tw 3.443735 Tw (can just call ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (with a single argument. In our example you can just write ) Tj /F4 10 Tf (trace =) Tj T* 0 Tw 1.056342 Tw (decorator\(_trace\)) Tj /F1 10 Tf (. The ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (function can also be used as a signature-changing decorator,) Tj T* 0 Tw 3.177752 Tw (just as ) Tj /F4 10 Tf (classmethod ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (staticmethod) Tj /F1 10 Tf (. However, ) Tj /F4 10 Tf (classmethod ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (staticmethod ) Tj /F1 10 Tf (return) Tj T* 0 Tw 1.693615 Tw (generic objects which are not callable, while ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (returns signature-preserving decorators, i.e.) Tj T* 0 Tw (functions of a single argument. For instance, you can write directly) Tj T* ET
+BT 1 0 0 1 0 86 Tm .643876 Tw 12 TL /F1 10 Tf 0 0 0 rg (It may be annoying to write a caller function \(like the ) Tj /F4 10 Tf (_trace ) Tj /F1 10 Tf (function above\) and then a trivial wrapper) Tj T* 0 Tw 1.510888 Tw (\() Tj /F4 10 Tf (def) Tj ( ) Tj (trace\(f\):) Tj ( ) Tj (return) Tj ( ) Tj (decorator\(_trace,) Tj ( ) Tj (f\)) Tj /F1 10 Tf (\) every time. For this reason, the ) Tj /F4 10 Tf (decorator) Tj T* 0 Tw .334269 Tw /F1 10 Tf (module provides an easy shortcut to convert the caller function into a signature-preserving decorator: you) Tj T* 0 Tw 7.364269 Tw (can just call ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (with a single argument. In our example you can just write) Tj T* 0 Tw .951647 Tw /F4 10 Tf (trace) Tj ( ) Tj (=) Tj ( ) Tj (decorator\(_trace\)) Tj /F1 10 Tf (. The ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (function can also be used as a signature-changing) Tj T* 0 Tw 1.077752 Tw (decorator, just as ) Tj /F4 10 Tf (classmethod ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (staticmethod) Tj /F1 10 Tf (. However, ) Tj /F4 10 Tf (classmethod ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (staticmethod) Tj T* 0 Tw .531797 Tw /F1 10 Tf (return generic objects which are not callable, while ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (returns signature-preserving decorators,) Tj T* 0 Tw (i.e. functions of a single argument. For instance, you can write directly) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 491.6236 cm
+1 0 0 1 62.69291 560.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -2580,23 +2631,23 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 60 re B*
+n -6 -6 468.6898 72 re B*
Q
q
-BT 1 0 0 1 0 38 Tm 12 TL /F4 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 /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (trace) Tj 0 0 0 rg (\() Tj (f) Tj (,) Tj ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\):) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (print) Tj /F4 10 Tf 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ("calling ) Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg ( with args ) Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg (, ) Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg (") Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (%) Tj 0 0 0 rg ( ) Tj (\() Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__name__) Tj (,) Tj ( ) Tj (args) Tj (,) Tj ( ) Tj (kw) Tj (\)\)) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (f) Tj (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\)) Tj T* ET
+BT 1 0 0 1 0 50 Tm 12 TL /F4 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 /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (trace) Tj 0 0 0 rg (\() Tj (f) Tj (,) Tj ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\):) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj (kwstr) Tj ( ) 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 (\() Tj .729412 .129412 .129412 rg (') Tj /F3 10 Tf .733333 .4 .533333 rg (%r) Tj /F4 10 Tf .729412 .129412 .129412 rg (: ) Tj /F3 10 Tf .733333 .4 .533333 rg (%r) Tj /F4 10 Tf .729412 .129412 .129412 rg (') Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (%) Tj 0 0 0 rg ( ) Tj (\() Tj (k) Tj (,) Tj ( ) Tj (kw) Tj ([) Tj (k) Tj (]\)) Tj ( ) Tj /F3 10 Tf 0 .501961 0 rg (for) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (k) Tj ( ) Tj /F3 10 Tf .666667 .133333 1 rg (in) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (sorted) Tj 0 0 0 rg (\() Tj (kw) Tj (\)\)) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (print) Tj /F4 10 Tf 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ("calling ) Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg ( with args ) Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg (, {) Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg (}") Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (%) Tj 0 0 0 rg ( ) Tj (\() Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__name__) Tj (,) Tj ( ) Tj (args) Tj (,) Tj ( ) Tj (kwstr) Tj (\)\)) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (f) Tj (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\)) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 459.6236 cm
+1 0 0 1 62.69291 528.8236 cm
q
BT 1 0 0 1 0 14 Tm 1.806654 Tw 12 TL /F1 10 Tf 0 0 0 rg (and now ) Tj /F4 10 Tf (trace ) Tj /F1 10 Tf (will be a decorator. Actually ) Tj /F4 10 Tf (trace ) Tj /F1 10 Tf (is a ) Tj /F4 10 Tf (partial ) Tj /F1 10 Tf (object which can be used as a) Tj T* 0 Tw (decorator:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 414.4236 cm
+1 0 0 1 62.69291 483.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -2616,14 +2667,14 @@ Q
Q
Q
q
-1 0 0 1 62.69291 394.4236 cm
+1 0 0 1 62.69291 463.6236 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 313.2236 cm
+1 0 0 1 62.69291 382.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -2643,25 +2694,25 @@ Q
Q
Q
q
-1 0 0 1 62.69291 281.2236 cm
+1 0 0 1 62.69291 350.4236 cm
q
BT 1 0 0 1 0 14 Tm 2.44686 Tw 12 TL /F1 10 Tf 0 0 0 rg (If you are using an old Python version \(Python 2.4\) the ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (module provides a poor man) Tj T* 0 Tw (replacement for ) Tj /F4 10 Tf (functools.partial) Tj /F1 10 Tf (.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 248.2236 cm
+1 0 0 1 62.69291 317.4236 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 206.2236 cm
+1 0 0 1 62.69291 275.4236 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 /F4 10 Tf (stdin) Tj /F1 10 Tf (, 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
q
-1 0 0 1 62.69291 77.02362 cm
+1 0 0 1 62.69291 98.22362 cm
q
q
1 0 0 1 0 0 cm
@@ -2671,10 +2722,10 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 120 re B*
+n -6 -6 468.6898 168 re B*
Q
q
-BT 1 0 0 1 0 98 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (blocking) Tj 0 0 0 rg (\() Tj (not_avail) Tj (\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (blocking) Tj 0 0 0 rg (\() Tj (f) Tj (,) Tj ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (if) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf .666667 .133333 1 rg (not) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (hasattr) Tj 0 0 0 rg (\() Tj (f) Tj (,) Tj ( ) Tj .729412 .129412 .129412 rg ("thread") Tj 0 0 0 rg (\):) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# no thread running) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (set_result) Tj 0 0 0 rg (\(\):) Tj ( ) Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (result) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (f) Tj (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\)) Tj T* ( ) Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (thread) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (threading) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Thread) Tj (\() Tj 0 .501961 0 rg (None) Tj 0 0 0 rg (,) Tj ( ) Tj (set_result) Tj (\)) Tj T* ( ) Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (thread) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (start) Tj (\(\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (not_avail) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (elif) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (thread) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (isAlive) Tj (\(\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (not_avail) Tj T* ET
+BT 1 0 0 1 0 146 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (blocking) Tj 0 0 0 rg (\() Tj (not_avail) Tj (\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (blocking) Tj 0 0 0 rg (\() Tj (f) Tj (,) Tj ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (if) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf .666667 .133333 1 rg (not) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (hasattr) Tj 0 0 0 rg (\() Tj (f) Tj (,) Tj ( ) Tj .729412 .129412 .129412 rg ("thread") Tj 0 0 0 rg (\):) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# no thread running) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (set_result) Tj 0 0 0 rg (\(\):) Tj ( ) Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (result) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (f) Tj (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\)) Tj T* ( ) Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (thread) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (threading) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Thread) Tj (\() Tj 0 .501961 0 rg (None) Tj 0 0 0 rg (,) Tj ( ) Tj (set_result) Tj (\)) Tj T* ( ) Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (thread) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (start) Tj (\(\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (not_avail) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (elif) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (thread) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (isAlive) Tj (\(\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (not_avail) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (else) Tj /F4 10 Tf 0 0 0 rg (:) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# the thread is ended, return the stored result) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (del) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (thread) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (result) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (decorator) Tj (\() Tj (blocking) Tj (\)) Tj T* ET
Q
Q
Q
@@ -2683,40 +2734,20 @@ Q
endstream
endobj
-% 'R92': class PDFStream
-92 0 obj
+% 'R95': class PDFStream
+95 0 obj
% page stream
-<< /Length 6963 >>
+<< /Length 6669 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 703.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
-BT 1 0 0 1 0 38 Tm 12 TL /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (else) Tj /F4 10 Tf 0 0 0 rg (:) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# the thread is ended, return the stored result) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (del) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (thread) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (f) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (result) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (decorator) Tj (\() Tj (blocking) Tj (\)) Tj T* ET
-Q
-Q
-Q
-Q
-Q
-q
-1 0 0 1 62.69291 671.8236 cm
+1 0 0 1 62.69291 741.0236 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 /F4 10 Tf (blocking ) Tj /F1 10 Tf (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 422.6236 cm
+1 0 0 1 62.69291 491.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -2736,25 +2767,26 @@ Q
Q
Q
q
-1 0 0 1 62.69291 389.6236 cm
+1 0 0 1 62.69291 458.8236 cm
q
BT 1 0 0 1 0 3.5 Tm 21 TL /F3 17.5 Tf 0 0 0 rg (async) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 323.6236 cm
+1 0 0 1 62.69291 416.8236 cm
q
-BT 1 0 0 1 0 50 Tm 1.647485 Tw 12 TL /F1 10 Tf 0 0 0 rg (We have just seen an examples of a simple decorator factory, implemented as a function returning a) Tj T* 0 Tw .29784 Tw (decorator. For more complex situations, it is more convenient to implement decorator factories as classes) Tj T* 0 Tw .657674 Tw (returning callable objects that can be used as signature-preserving decorators. The suggested pattern to) Tj T* 0 Tw 2.109398 Tw (do that is to introduce a helper method ) Tj /F4 10 Tf (call\(self, func, *args, **kw\) ) Tj /F1 10 Tf (and to call it in the) Tj T* 0 Tw /F4 10 Tf (__call__\(self, func\) ) Tj /F1 10 Tf (method.) Tj T* ET
+0 0 0 rg
+BT 1 0 0 1 0 26 Tm /F1 10 Tf 12 TL 1.647485 Tw (We have just seen an examples of a simple decorator factory, implemented as a function returning a) Tj T* 0 Tw .29784 Tw (decorator. For more complex situations, it is more convenient to implement decorator factories as classes) Tj T* 0 Tw (returning callable objects that can be converted into decorators.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 269.6236 cm
+1 0 0 1 62.69291 350.8236 cm
q
-BT 1 0 0 1 0 38 Tm .166654 Tw 12 TL /F1 10 Tf 0 0 0 rg (As an example, here I show a decorator which is able to convert a blocking function into an asynchronous) Tj T* 0 Tw .437633 Tw (function. The function, when called, is executed in a separate thread. Moreover, it is possible to set three) Tj T* 0 Tw .074597 Tw (callbacks ) Tj /F4 10 Tf (on_success) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (on_failure ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (on_closing) Tj /F1 10 Tf (, to specify how to manage the function call. The) Tj T* 0 Tw (implementation is the following:) Tj T* ET
+BT 1 0 0 1 0 50 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 2.477126 Tw (asynchronous function. The function, when called, is executed in a separate thread. Moreover, it is) Tj T* 0 Tw .288443 Tw (possible to set three callbacks ) Tj /F4 10 Tf (on_success) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (on_failure ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (on_closing) Tj /F1 10 Tf (, to specify how to manage) Tj T* 0 Tw 1.854724 Tw (the function call \(of course the code here is just an example, it is not a recommended way of doing) Tj T* 0 Tw (multi-threaded programming\). The implementation is the following:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 212.4236 cm
+1 0 0 1 62.69291 293.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -2774,7 +2806,7 @@ Q
Q
Q
q
-1 0 0 1 62.69291 155.2236 cm
+1 0 0 1 62.69291 236.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -2794,7 +2826,7 @@ Q
Q
Q
q
-1 0 0 1 62.69291 98.02362 cm
+1 0 0 1 62.69291 179.2236 cm
q
q
1 0 0 1 0 0 cm
@@ -2813,17 +2845,37 @@ Q
Q
Q
Q
+q
+1 0 0 1 62.69291 86.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
+BT 1 0 0 1 0 62 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (class) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf 0 0 1 rg (Async) Tj /F4 10 Tf 0 0 0 rg (\() Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\):) Tj T* ( ) Tj /F6 10 Tf .729412 .129412 .129412 rg (""") Tj T* ( A decorator converting blocking functions into asynchronous) Tj T* ( functions, by using threads or processes. Examples:) Tj T* T* ( async_with_threads = Async\(threading.Thread\)) Tj T* ET
+Q
+Q
+Q
+Q
+Q
endstream
endobj
-% 'R93': class PDFStream
-93 0 obj
+% 'R96': class PDFStream
+96 0 obj
% page stream
-<< /Length 7235 >>
+<< /Length 8071 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 331.8236 cm
+1 0 0 1 62.69291 415.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -2833,30 +2885,30 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 432 re B*
+n -6 -6 468.6898 348 re B*
Q
q
-BT 1 0 0 1 0 410 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (class) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf 0 0 1 rg (Async) Tj /F4 10 Tf 0 0 0 rg (\() Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\):) Tj T* ( ) Tj /F6 10 Tf .729412 .129412 .129412 rg (""") Tj T* ( A decorator converting blocking functions into asynchronous) Tj T* ( functions, by using threads or processes. Examples:) Tj T* T* ( async_with_threads = Async\(threading.Thread\)) Tj T* ( async_with_processes = Async\(multiprocessing.Process\)) Tj T* ( """) Tj /F4 10 Tf 0 0 0 rg T* T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 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 ( ) Tj (threadfactory) Tj (\):) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (threadfactory) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (threadfactory) Tj T* T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 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 ( ) Tj (func) Tj (,) Tj ( ) Tj (on_success) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (on_success) Tj (,) Tj T* ( ) Tj (on_failure) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (on_failure) Tj (,) Tj ( ) Tj (on_closing) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (on_closing) Tj (\):) Tj T* ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# every decorated function has its own independent thread counter) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (counter) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (itertools) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (count) Tj (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (\)) Tj T* ( ) Tj (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (on_success) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (on_success) Tj T* ( ) Tj (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (on_failure) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (on_failure) Tj T* ( ) Tj (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (on_closing) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (on_closing) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (decorator) Tj (\() Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (call) Tj (,) Tj ( ) Tj (func) Tj (\)) Tj T* T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 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 ( ) Tj (func) Tj (,) Tj ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (func_wrapper) Tj 0 0 0 rg (\(\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (try) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj (result) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (func) Tj (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (except) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (on_failure) Tj (\() Tj (sys) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (exc_info) Tj (\(\)\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (else) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (on_success) Tj (\() Tj (result) Tj (\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (finally) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (on_closing) Tj (\(\)) Tj T* ( ) Tj (name) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg (') Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg (-) Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg (') Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (%) Tj 0 0 0 rg ( ) Tj (\() Tj (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__name__) Tj (,) Tj ( ) Tj 0 .501961 0 rg (next) Tj 0 0 0 rg (\() Tj (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (counter) Tj (\)\)) Tj T* ( ) Tj (thread) Tj ( ) 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 (threadfactory) Tj (\() Tj 0 .501961 0 rg (None) Tj 0 0 0 rg (,) Tj ( ) Tj (func_wrapper) Tj (,) Tj ( ) Tj (name) Tj (\)) Tj T* ( ) Tj (thread) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (start) Tj (\(\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (thread) Tj T* ET
+BT 1 0 0 1 0 326 Tm 12 TL /F6 10 Tf .729412 .129412 .129412 rg ( async_with_processes = Async\(multiprocessing.Process\)) Tj T* ( """) Tj /F4 10 Tf 0 0 0 rg T* T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 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 ( ) Tj (threadfactory) Tj (,) Tj ( ) Tj (on_success) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (on_success) Tj (,) Tj T* ( ) Tj (on_failure) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (on_failure) Tj (,) Tj ( ) Tj (on_closing) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg (on_closing) Tj (\):) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (threadfactory) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (threadfactory) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (on_success) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (on_success) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (on_failure) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (on_failure) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (on_closing) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (on_closing) Tj T* T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 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 ( ) Tj (func) Tj (,) Tj ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (try) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj (counter) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (counter) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (except) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf .823529 .254902 .227451 rg (AttributeError) Tj /F4 10 Tf 0 0 0 rg (:) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# instantiate the counter at the first call) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj (counter) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (counter) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (itertools) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (count) Tj (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (\)) Tj T* ( ) Tj (name) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj .729412 .129412 .129412 rg (') Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg (-) Tj /F3 10 Tf .733333 .4 .533333 rg (%s) Tj /F4 10 Tf .729412 .129412 .129412 rg (') Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (%) Tj 0 0 0 rg ( ) Tj (\() Tj (func) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (__name__) Tj (,) Tj ( ) Tj 0 .501961 0 rg (next) Tj 0 0 0 rg (\() Tj (counter) Tj (\)\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (func_wrapper) Tj 0 0 0 rg (\(\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (try) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj (result) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (func) Tj (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kw) Tj (\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (except) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (on_failure) Tj (\() Tj (sys) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (exc_info) Tj (\(\)\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (else) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (on_success) Tj (\() Tj (result) Tj (\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (finally) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (on_closing) Tj (\(\)) Tj T* ( ) Tj (thread) Tj ( ) 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 (threadfactory) Tj (\() Tj 0 .501961 0 rg (None) Tj 0 0 0 rg (,) Tj ( ) Tj (func_wrapper) Tj (,) Tj ( ) Tj (name) Tj (\)) Tj T* ( ) Tj (thread) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (start) Tj (\(\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (thread) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 299.8236 cm
+1 0 0 1 62.69291 383.8236 cm
q
BT 1 0 0 1 0 14 Tm .865984 Tw 12 TL /F1 10 Tf 0 0 0 rg (The decorated function returns the current execution thread, which can be stored and checked later, for) Tj T* 0 Tw (instance to verify that the thread ) Tj /F4 10 Tf (.isAlive\(\)) Tj /F1 10 Tf (.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 257.8236 cm
+1 0 0 1 62.69291 341.8236 cm
q
0 0 0 rg
BT 1 0 0 1 0 26 Tm /F1 10 Tf 12 TL .691654 Tw (Here is an example of usage. Suppose one wants to write some data to an external resource which can) Tj T* 0 Tw .21683 Tw (be accessed by a single user at once \(for instance a printer\). Then the access to the writing function must) Tj T* 0 Tw (be locked. Here is a minimalistic example:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 104.6236 cm
+1 0 0 1 62.69291 188.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -2869,7 +2921,33 @@ q
n -6 -6 468.6898 144 re B*
Q
q
-BT 1 0 0 1 0 122 Tm 12 TL /F4 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (async) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (Async) Tj (\() Tj (threading) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Thread) Tj (\)) Tj T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (datalist) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj ([]) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# for simplicity the written data are stored into a list.) Tj /F4 10 Tf 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj .666667 .133333 1 rg (@async) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (write) Tj 0 0 0 rg (\() Tj (data) Tj (\):) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# append data to the datalist by locking) Tj /F4 10 Tf 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (with) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (threading) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Lock) Tj (\(\):) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj (time) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (sleep) Tj (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (\)) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# emulate some long running operation) Tj /F4 10 Tf 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj (datalist) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (append) Tj (\() Tj (data) Tj (\)) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# other operations not requiring a lock here) Tj T* ET
+BT 1 0 0 1 0 122 Tm 12 TL /F4 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (async) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (decorator) Tj (\() Tj (Async) Tj (\() Tj (threading) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Thread) Tj (\)\)) Tj T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (datalist) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj ([]) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# for simplicity the written data are stored into a list.) Tj /F4 10 Tf 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj .666667 .133333 1 rg (@async) Tj 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (write) Tj 0 0 0 rg (\() Tj (data) Tj (\):) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# append data to the datalist by locking) Tj /F4 10 Tf 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (with) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (threading) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (Lock) Tj (\(\):) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj (time) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (sleep) Tj (\() Tj .4 .4 .4 rg (1) Tj 0 0 0 rg (\)) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# emulate some long running operation) Tj /F4 10 Tf 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj (datalist) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (append) Tj (\() Tj (data) Tj (\)) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# other operations not requiring a lock here) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 156.6236 cm
+q
+BT 1 0 0 1 0 14 Tm .905868 Tw 12 TL /F1 10 Tf 0 0 0 rg (Each call to ) Tj /F4 10 Tf (write ) Tj /F1 10 Tf (will create a new writer thread, but there will be no synchronization problems since) Tj T* 0 Tw /F4 10 Tf (write ) Tj /F1 10 Tf (is locked.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 87.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 60 re B*
+Q
+q
+BT 1 0 0 1 0 38 Tm 12 TL /F4 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (write) Tj (\() Tj .729412 .129412 .129412 rg ("data1") Tj 0 0 0 rg (\)) Tj T* .4 .4 .4 rg (<) Tj 0 0 0 rg (Thread) Tj (\() Tj (write) Tj .4 .4 .4 rg (-) Tj (1) Tj 0 0 0 rg (,) Tj ( ) Tj (started) Tj .4 .4 .4 rg (...) 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 (time) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (sleep) Tj (\() Tj .4 .4 .4 rg (.) Tj (1) Tj 0 0 0 rg (\)) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# wait a bit, so we are sure data2 is written after data1) Tj /F4 10 Tf 0 0 0 rg T* ET
Q
Q
Q
@@ -2878,20 +2956,46 @@ Q
endstream
endobj
-% 'R94': class PDFStream
-94 0 obj
+% 'R97': class PDFStream
+97 0 obj
% page stream
-<< /Length 7675 >>
+<< /Length 6932 >>
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
+1 0 0 1 62.69291 655.8236 cm
q
-BT 1 0 0 1 0 14 Tm .905868 Tw 12 TL /F1 10 Tf 0 0 0 rg (Each call to ) Tj /F4 10 Tf (write ) Tj /F1 10 Tf (will create a new writer thread, but there will be no synchronization problems since) Tj T* 0 Tw /F4 10 Tf (write ) Tj /F1 10 Tf (is locked.) Tj T* ET
+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
+BT 1 0 0 1 0 86 Tm 12 TL /F4 10 Tf 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (write) Tj (\() Tj .729412 .129412 .129412 rg ("data2") Tj 0 0 0 rg (\)) Tj T* .4 .4 .4 rg (<) Tj 0 0 0 rg (Thread) Tj (\() Tj (write) Tj .4 .4 .4 rg (-) Tj (2) Tj 0 0 0 rg (,) Tj ( ) Tj (started) Tj .4 .4 .4 rg (...) 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 (time) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (sleep) Tj (\() Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (\)) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# wait for the writers to complete) Tj /F4 10 Tf 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (print) Tj /F4 10 Tf 0 0 0 rg (\() Tj (datalist) Tj (\)) Tj T* ([) Tj .729412 .129412 .129412 rg ('data1') Tj 0 0 0 rg (,) Tj ( ) Tj .729412 .129412 .129412 rg ('data2') Tj 0 0 0 rg (]) Tj T* ET
+Q
+Q
+Q
Q
Q
q
-1 0 0 1 62.69291 575.8236 cm
+1 0 0 1 62.69291 622.8236 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 592.8236 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 /F4 10 Tf (contextmanager ) Tj /F1 10 Tf (decorator, able to convert) Tj T* 0 Tw (generator functions into ) Tj /F4 10 Tf (_GeneratorContextManager ) Tj /F1 10 Tf (factories. For instance if you write) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 499.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -2901,35 +3005,108 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 156 re B*
+n -6 -6 468.6898 84 re B*
Q
q
-BT 1 0 0 1 0 134 Tm 12 TL /F4 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (write) Tj (\() Tj .729412 .129412 .129412 rg ("data1") Tj 0 0 0 rg (\)) Tj T* .4 .4 .4 rg (<) Tj 0 0 0 rg (Thread) Tj (\() Tj (write) Tj .4 .4 .4 rg (-) Tj (1) Tj 0 0 0 rg (,) Tj ( ) Tj (started) Tj .4 .4 .4 rg (...) 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 (time) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (sleep) Tj (\() Tj .4 .4 .4 rg (.) Tj (1) Tj 0 0 0 rg (\)) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# wait a bit, so we are sure data2 is written after data1) Tj /F4 10 Tf 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (write) Tj (\() Tj .729412 .129412 .129412 rg ("data2") Tj 0 0 0 rg (\)) Tj T* .4 .4 .4 rg (<) Tj 0 0 0 rg (Thread) Tj (\() Tj (write) Tj .4 .4 .4 rg (-) Tj (2) Tj 0 0 0 rg (,) Tj ( ) Tj (started) Tj .4 .4 .4 rg (...) 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 (time) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (sleep) Tj (\() Tj .4 .4 .4 rg (2) Tj 0 0 0 rg (\)) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# wait for the writers to complete) Tj /F4 10 Tf 0 0 0 rg T* T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (print) Tj /F4 10 Tf 0 0 0 rg (\() Tj (datalist) Tj (\)) Tj T* ([) Tj .729412 .129412 .129412 rg ('data1') Tj 0 0 0 rg (,) Tj ( ) Tj .729412 .129412 .129412 rg ('data2') Tj 0 0 0 rg (]) Tj T* ET
+BT 1 0 0 1 0 62 Tm 12 TL /F4 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (from) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf 0 0 1 rg (contextlib) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (import) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (contextmanager) Tj 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 /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (before_after) Tj 0 0 0 rg (\() Tj (before) Tj (,) Tj ( ) Tj (after) Tj (\):) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (print) Tj /F4 10 Tf 0 0 0 rg (\() Tj (before) Tj (\)) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (yield) Tj /F4 10 Tf 0 0 0 rg T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (print) Tj /F4 10 Tf 0 0 0 rg (\() Tj (after) Tj (\)) Tj T* ET
+Q
+Q
Q
Q
Q
+q
+1 0 0 1 62.69291 467.6236 cm
+q
+BT 1 0 0 1 0 14 Tm .955976 Tw 12 TL /F1 10 Tf 0 0 0 rg (then ) Tj /F4 10 Tf (before_after ) Tj /F1 10 Tf (is a factory function returning ) Tj /F4 10 Tf (_GeneratorContextManager ) Tj /F1 10 Tf (objects which can) Tj T* 0 Tw (be used with the ) Tj /F4 10 Tf (with ) Tj /F1 10 Tf (statement:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 542.8236 cm
+1 0 0 1 62.69291 350.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 108 re B*
+Q
+q
+BT 1 0 0 1 0 86 Tm 12 TL /F4 10 Tf .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (ba) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (before_after) Tj (\() Tj .729412 .129412 .129412 rg ('BEFORE') Tj 0 0 0 rg (,) Tj ( ) Tj .729412 .129412 .129412 rg ('AFTER') Tj 0 0 0 rg (\)) Tj T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (type) Tj 0 0 0 rg (\() Tj (ba) Tj (\)) Tj T* .4 .4 .4 rg (<) Tj /F3 10 Tf 0 .501961 0 rg (class) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (') Tj /F3 10 Tf 0 0 1 rg (contextlib) Tj /F4 10 Tf .4 .4 .4 rg (.) Tj 0 0 0 rg (_GeneratorContextManager) Tj .729412 .129412 .129412 rg (') Tj (>) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (with) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (ba) Tj (:) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (print) Tj /F4 10 Tf 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ('hello') Tj 0 0 0 rg (\)) Tj T* (BEFORE) Tj T* (hello) Tj T* (AFTER) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 306.4236 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 /F4 10 Tf (with ) Tj /F1 10 Tf (block was executed in the place of the ) Tj /F4 10 Tf (yield ) Tj /F1 10 Tf (expression in) Tj T* 0 Tw 2.146342 Tw (the generator function. In Python 3.2 ) Tj /F4 10 Tf (_GeneratorContextManager ) Tj /F1 10 Tf (objects were enhanced with a) Tj T* 0 Tw /F4 10 Tf (__call__ ) Tj /F1 10 Tf (method, so that they can be used as decorators as in this example:) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 189.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 108 re B*
+Q
+q
+BT 1 0 0 1 0 86 Tm 12 TL /F4 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 /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (hello) Tj 0 0 0 rg (\(\):) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (print) Tj /F4 10 Tf 0 0 0 rg (\() Tj .729412 .129412 .129412 rg ('hello') Tj 0 0 0 rg (\)) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg T* .4 .4 .4 rg (>) Tj (>) Tj (>) Tj 0 0 0 rg ( ) Tj (hello) Tj (\(\)) Tj T* (BEFORE) Tj T* (hello) Tj T* (AFTER) Tj T* ET
+Q
+Q
+Q
+Q
+Q
+q
+1 0 0 1 62.69291 85.22362 cm
+q
+BT 1 0 0 1 0 86 Tm .20561 Tw 12 TL /F1 10 Tf 0 0 0 rg (The ) Tj /F4 10 Tf (ba ) Tj /F1 10 Tf (decorator is basically inserting a ) Tj /F4 10 Tf (with) Tj ( ) Tj (ba: ) Tj /F1 10 Tf (block inside the function. However there two issues: ) Tj T* 0 Tw .973555 Tw (the first is that ) Tj /F4 10 Tf (_GeneratorContextManager ) Tj /F1 10 Tf (objects are callable only in Python 3.2, so the previous ) Tj T* 0 Tw 2.758314 Tw (example will break in older versions of Python; the second is that ) Tj /F4 10 Tf (_GeneratorContextManager ) Tj T* 0 Tw .503318 Tw /F1 10 Tf (objects do not preserve the signature of the decorated functions: the decorated ) Tj /F4 10 Tf (hello ) Tj /F1 10 Tf (function here will ) Tj T* 0 Tw 1.07784 Tw (have a generic signature ) Tj /F4 10 Tf (hello\(*args,) Tj ( ) Tj (**kwargs\) ) Tj /F1 10 Tf (but will break when called with more than zero ) Tj T* 0 Tw 7.708314 Tw (arguments. For such reasons the decorator module, starting with release 3.4, offers a ) Tj T* 0 Tw .616647 Tw /F4 10 Tf (decorator.contextmanager ) Tj /F1 10 Tf (decorator that solves both problems and works even in Python 2.5. The ) Tj T* 0 Tw .34998 Tw (usage is the same and factories decorated with ) Tj /F4 10 Tf (decorator.contextmanager ) Tj /F1 10 Tf (will returns instances of) Tj T* 0 Tw ET
+Q
+Q
+
+endstream
+endobj
+% 'R98': class PDFStream
+98 0 obj
+% page stream
+<< /Length 8146 >>
+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 3.295681 Tw 12 TL /F4 10 Tf 0 0 0 rg (ContextManager) Tj /F1 10 Tf (, a subclass of ) Tj /F4 10 Tf (contextlib._GeneratorContextManager ) Tj /F1 10 Tf (with a ) Tj /F4 10 Tf (__call__) Tj T* 0 Tw /F1 10 Tf (method acting as a signature-preserving decorator.) 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 (The ) Tj /F3 17.5 Tf (FunctionMaker ) Tj /F2 17.5 Tf (class) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 476.8236 cm
+1 0 0 1 62.69291 642.0236 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 /F4 10 Tf (decorator ) Tj /F1 10 Tf (module is implemented. The basic) Tj T* 0 Tw 1.545868 Tw (building block is a ) Tj /F4 10 Tf (FunctionMaker ) Tj /F1 10 Tf (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 /F4 10 Tf (FunctionMaker ) Tj /F1 10 Tf (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 /F4 10 Tf (decorator_apply) Tj /F1 10 Tf (\).) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 434.8236 cm
+1 0 0 1 62.69291 600.0236 cm
q
BT 1 0 0 1 0 26 Tm .414597 Tw 12 TL /F4 10 Tf 0 0 0 rg (FunctionMaker ) Tj /F1 10 Tf (provides a ) Tj /F4 10 Tf (.create ) Tj /F1 10 Tf (classmethod which takes as input the name, signature, and body) Tj T* 0 Tw .632927 Tw (of the function we want to generate as well as the execution environment were the function is generated) Tj T* 0 Tw (by ) Tj /F4 10 Tf (exec) Tj /F1 10 Tf (. Here is an example:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 341.6236 cm
+1 0 0 1 62.69291 506.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -2949,25 +3126,25 @@ Q
Q
Q
q
-1 0 0 1 62.69291 309.6236 cm
+1 0 0 1 62.69291 474.8236 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 /F4 10 Tf (% ) Tj /F1 10 Tf (sign!) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 267.6236 cm
+1 0 0 1 62.69291 432.8236 cm
q
BT 1 0 0 1 0 26 Tm 1.995433 Tw 12 TL /F4 10 Tf 0 0 0 rg (FunctionMaker.create ) Tj /F1 10 Tf (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 /F4 10 Tf (__doc__) Tj /F1 10 Tf (.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 225.6236 cm
+1 0 0 1 62.69291 390.8236 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 /F4 10 Tf (addsource=True ) Tj /F1 10 Tf (and a ) Tj /F4 10 Tf (__source__ ) Tj /F1 10 Tf (attribute will be added to the) Tj T* 0 Tw (generated function:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 132.4236 cm
+1 0 0 1 62.69291 297.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -2987,46 +3164,40 @@ Q
Q
Q
q
-1 0 0 1 62.69291 88.42362 cm
+1 0 0 1 62.69291 157.6236 cm
+q
+BT 1 0 0 1 0 122 Tm .870651 Tw 12 TL /F4 10 Tf 0 0 0 rg (FunctionMaker.create ) Tj /F1 10 Tf (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 /F4 10 Tf (FunctionMaker.create ) Tj /F1 10 Tf (instead of ) Tj /F4 10 Tf (decorator) Tj /F1 10 Tf (, 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 /F4 10 Tf (__init__ ) Tj /F1 10 Tf (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 /F4 10 Tf (FunctionMaker.create) Tj T* 0 Tw 3.405814 Tw /F1 10 Tf (is a function, a ) Tj /F4 10 Tf (FunctionMaker ) Tj /F1 10 Tf (object is instantiated internally, with attributes ) Tj /F4 10 Tf (args) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (varargs) Tj /F1 10 Tf (,) Tj T* 0 Tw 5.509982 Tw /F4 10 Tf (keywords ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (defaults ) Tj /F1 10 Tf (which are the the return values of the standard library function) Tj T* 0 Tw .561318 Tw /F4 10 Tf (inspect.getargspec) Tj /F1 10 Tf (. For each argument in the ) Tj /F4 10 Tf (args ) Tj /F1 10 Tf (\(which is a list of strings containing the names) Tj T* 0 Tw 1.599985 Tw (of the mandatory arguments\) an attribute ) Tj /F4 10 Tf (arg0) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (arg1) Tj /F1 10 Tf (, ..., ) Tj /F4 10 Tf (argN ) Tj /F1 10 Tf (is also generated. Finally, there is a) Tj T* 0 Tw /F4 10 Tf (signature ) Tj /F1 10 Tf (attribute, a string with the signature of the original function.) Tj T* ET
+Q
+Q
+q
+1 0 0 1 62.69291 79.62362 cm
q
-BT 1 0 0 1 0 26 Tm .870651 Tw 12 TL /F4 10 Tf 0 0 0 rg (FunctionMaker.create ) Tj /F1 10 Tf (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 /F4 10 Tf (FunctionMaker.create ) Tj /F1 10 Tf (instead of ) Tj /F4 10 Tf (decorator) Tj /F1 10 Tf (, since it gives you) Tj T* 0 Tw ET
+BT 1 0 0 1 0 62 Tm 4.63311 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice that while I do not have plans to change or remove the functionality provided in the) Tj T* 0 Tw 1.00936 Tw /F4 10 Tf (FunctionMaker ) Tj /F1 10 Tf (class, I do not guarantee that it will stay unchanged forever. For instance, right now I) Tj T* 0 Tw .791318 Tw (am using the traditional string interpolation syntax for function templates, but Python 2.6 and Python 3.0) Tj T* 0 Tw .712093 Tw (provide a newer interpolation syntax and I may use the new syntax in the future. On the other hand, the) Tj T* 0 Tw .639985 Tw (functionality provided by ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (has been there from version 0.1 and it is guaranteed to stay there) Tj T* 0 Tw (forever.) Tj T* ET
Q
Q
endstream
endobj
-% 'R95': class PDFStream
-95 0 obj
+% 'R99': class PDFStream
+99 0 obj
% page stream
-<< /Length 7237 >>
+<< /Length 7325 >>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 669.0236 cm
-q
-BT 1 0 0 1 0 86 Tm 1.36686 Tw 12 TL /F1 10 Tf 0 0 0 rg (direct access to the body of the generated function. For instance, suppose you want to instrument the) Tj T* 0 Tw .372209 Tw /F4 10 Tf (__init__ ) Tj /F1 10 Tf (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 /F4 10 Tf (FunctionMaker.create) Tj T* 0 Tw 3.405814 Tw /F1 10 Tf (is a function, a ) Tj /F4 10 Tf (FunctionMaker ) Tj /F1 10 Tf (object is instantiated internally, with attributes ) Tj /F4 10 Tf (args) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (varargs) Tj /F1 10 Tf (,) Tj T* 0 Tw 5.509982 Tw /F4 10 Tf (keywords ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (defaults ) Tj /F1 10 Tf (which are the the return values of the standard library function) Tj T* 0 Tw .561318 Tw /F4 10 Tf (inspect.getargspec) Tj /F1 10 Tf (. For each argument in the ) Tj /F4 10 Tf (args ) Tj /F1 10 Tf (\(which is a list of strings containing the names) Tj T* 0 Tw 1.599985 Tw (of the mandatory arguments\) an attribute ) Tj /F4 10 Tf (arg0) Tj /F1 10 Tf (, ) Tj /F4 10 Tf (arg1) Tj /F1 10 Tf (, ..., ) Tj /F4 10 Tf (argN ) Tj /F1 10 Tf (is also generated. Finally, there is a) Tj T* 0 Tw /F4 10 Tf (signature ) Tj /F1 10 Tf (attribute, a string with the signature of the original function.) Tj T* ET
-Q
-Q
-q
-1 0 0 1 62.69291 591.0236 cm
-q
-BT 1 0 0 1 0 62 Tm 4.63311 Tw 12 TL /F1 10 Tf 0 0 0 rg (Notice that while I do not have plans to change or remove the functionality provided in the) Tj T* 0 Tw 1.00936 Tw /F4 10 Tf (FunctionMaker ) Tj /F1 10 Tf (class, I do not guarantee that it will stay unchanged forever. For instance, right now I) Tj T* 0 Tw .791318 Tw (am using the traditional string interpolation syntax for function templates, but Python 2.6 and Python 3.0) Tj T* 0 Tw .712093 Tw (provide a newer interpolation syntax and I may use the new syntax in the future. On the other hand, the) Tj T* 0 Tw .639985 Tw (functionality provided by ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (has been there from version 0.1 and it is guaranteed to stay there) Tj T* 0 Tw (forever.) Tj T* ET
-Q
-Q
-q
-1 0 0 1 62.69291 558.0236 cm
+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 (Getting the source code) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 480.0236 cm
+1 0 0 1 62.69291 666.0236 cm
q
-BT 1 0 0 1 0 62 Tm 5.045529 Tw 12 TL /F1 10 Tf 0 0 0 rg (Internally ) Tj /F4 10 Tf (FunctionMaker.create ) Tj /F1 10 Tf (uses ) Tj /F4 10 Tf (exec ) Tj /F1 10 Tf (to generate the decorated function. Therefore) Tj T* 0 Tw 2.542126 Tw /F4 10 Tf (inspect.getsource ) Tj /F1 10 Tf (will not work for decorated functions. That means that the usual '??' trick in) Tj T* 0 Tw 2.163059 Tw (IPython will give you the \(right on the spot\) message ) Tj /F4 10 Tf (Dynamically generated function. No) Tj T* 0 Tw .563314 Tw (source code available) Tj /F1 10 Tf (. In the past I have considered this acceptable, since ) Tj /F4 10 Tf (inspect.getsource) Tj T* 0 Tw 1.790697 Tw /F1 10 Tf (does not really work even with regular decorators. In that case ) Tj /F4 10 Tf (inspect.getsource ) Tj /F1 10 Tf (gives you the) Tj T* 0 Tw (wrapper source code which is probably not what you want:) Tj T* ET
+BT 1 0 0 1 0 62 Tm 5.045529 Tw 12 TL /F1 10 Tf 0 0 0 rg (Internally ) Tj /F4 10 Tf (FunctionMaker.create ) Tj /F1 10 Tf (uses ) Tj /F4 10 Tf (exec ) Tj /F1 10 Tf (to generate the decorated function. Therefore) Tj T* 0 Tw 2.542126 Tw /F4 10 Tf (inspect.getsource ) Tj /F1 10 Tf (will not work for decorated functions. That means that the usual '??' 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 /F4 10 Tf (Dynamically) Tj ( ) Tj (generated) Tj ( ) Tj (function.) Tj ( ) Tj (No) Tj ( ) Tj (source) Tj ( ) Tj (code available) Tj /F1 10 Tf (. In the past I have considered) Tj T* 0 Tw .945366 Tw (this acceptable, since ) Tj /F4 10 Tf (inspect.getsource ) Tj /F1 10 Tf (does not really work even with regular decorators. In that) Tj T* 0 Tw (case ) Tj /F4 10 Tf (inspect.getsource ) Tj /F1 10 Tf (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 410.8236 cm
+1 0 0 1 62.69291 596.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -3046,7 +3217,7 @@ Q
Q
Q
q
-1 0 0 1 62.69291 305.6236 cm
+1 0 0 1 62.69291 491.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -3066,13 +3237,13 @@ Q
Q
Q
q
-1 0 0 1 62.69291 249.6236 cm
+1 0 0 1 62.69291 435.6236 cm
q
BT 1 0 0 1 0 38 Tm 1.471235 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,) Tj T* 0 Tw 1.541235 Tw (even in Python 2.7 and 3.1. There is however a workaround. The decorator module adds an attribute) Tj T* 0 Tw .103984 Tw /F4 10 Tf (.__wrapped__ ) Tj /F1 10 Tf (to the decorated function, containing a reference to the original function. The easy way to) Tj T* 0 Tw (get the source code is to call ) Tj /F4 10 Tf (inspect.getsource ) Tj /F1 10 Tf (on the undecorated function:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 144.4236 cm
+1 0 0 1 62.69291 330.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -3091,29 +3262,20 @@ Q
Q
Q
Q
-
-endstream
-endobj
-% 'R96': class PDFStream
-96 0 obj
-% page stream
-<< /Length 7379 >>
-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
+1 0 0 1 62.69291 297.4236 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 690.0236 cm
+1 0 0 1 62.69291 243.4236 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 /F4 10 Tf (decorator) Tj /F1 10 Tf (. You can use a ) Tj /F4 10 Tf (FunctionMaker ) Tj /F1 10 Tf (to implement that functionality as follows:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 572.8236 cm
+1 0 0 1 62.69291 126.2236 cm
q
q
1 0 0 1 0 0 cm
@@ -3133,25 +3295,34 @@ Q
Q
Q
q
-1 0 0 1 62.69291 540.8236 cm
+1 0 0 1 62.69291 94.22362 cm
q
BT 1 0 0 1 0 14 Tm .698314 Tw 12 TL /F4 10 Tf 0 0 0 rg (decorator_apply ) Tj /F1 10 Tf (sets the attribute ) Tj /F4 10 Tf (.__wrapped__ ) Tj /F1 10 Tf (of the generated function to the original function,) Tj T* 0 Tw (so that you can get the right source code.) Tj T* ET
Q
Q
+
+endstream
+endobj
+% 'R100': class PDFStream
+100 0 obj
+% page stream
+<< /Length 7498 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 498.8236 cm
+1 0 0 1 62.69291 729.0236 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 /F4 10 Tf (decorator ) Tj /F1 10 Tf (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 /F4 10 Tf (decorator_apply ) Tj /F1 10 Tf (to your toolbox and use it if you need to.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 444.8236 cm
+1 0 0 1 62.69291 675.0236 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 /F4 10 Tf (decorator_apply) Tj /F1 10 Tf (, 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 87.62362 cm
+1 0 0 1 62.69291 305.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -3161,53 +3332,24 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 348 re B*
+n -6 -6 468.6898 360 re B*
Q
q
-BT 1 0 0 1 0 326 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (class) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf 0 0 1 rg (TailRecursive) Tj /F4 10 Tf 0 0 0 rg (\() Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\):) Tj 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 /F4 10 Tf 0 0 0 rg T* T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 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 ( ) Tj (func) Tj (\):) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (func) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (func) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (firstcall) Tj ( ) 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 ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\(\)) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# sentinel) Tj /F4 10 Tf 0 0 0 rg T* T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 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 ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kwd) Tj (\):) Tj T* ( ) Tj (CONTINUE) Tj ( ) 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 T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (if) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (firstcall) Tj (:) Tj T* ( ) Tj (func) Tj ( ) 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 T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (firstcall) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (False) Tj 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (try) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (while) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (True) Tj 0 0 0 rg (:) Tj T* ( ) Tj (result) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (func) Tj (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kwd) Tj (\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (if) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (result) Tj ( ) Tj /F3 10 Tf .666667 .133333 1 rg (is) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (CONTINUE) Tj (:) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# update arguments) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj (args) Tj (,) Tj ( ) Tj (kwd) Tj ( ) 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 T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (else) Tj /F4 10 Tf 0 0 0 rg (:) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# last call) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (result) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (finally) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (firstcall) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (True) Tj 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (else) Tj /F4 10 Tf 0 0 0 rg (:) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# return the arguments of the tail call) Tj /F4 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 ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (args) Tj (,) Tj ( ) Tj (kwd) Tj T* ET
+BT 1 0 0 1 0 338 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (class) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf 0 0 1 rg (TailRecursive) Tj /F4 10 Tf 0 0 0 rg (\() Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\):) Tj 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 /F4 10 Tf 0 0 0 rg T* T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 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 ( ) Tj (func) Tj (\):) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (func) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (func) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (firstcall) Tj ( ) 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 ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (object) Tj 0 0 0 rg (\(\)) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# sentinel) Tj /F4 10 Tf 0 0 0 rg T* T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 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 ( ) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kwd) Tj (\):) Tj T* ( ) Tj (CONTINUE) Tj ( ) 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 T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (if) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (firstcall) Tj (:) Tj T* ( ) Tj (func) Tj ( ) 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 T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (firstcall) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (False) Tj 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (try) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (while) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 .501961 0 rg (True) Tj 0 0 0 rg (:) Tj T* ( ) Tj (result) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (func) Tj (\() Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (args) Tj (,) Tj ( ) Tj .4 .4 .4 rg (**) Tj 0 0 0 rg (kwd) Tj (\)) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (if) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (result) Tj ( ) Tj /F3 10 Tf .666667 .133333 1 rg (is) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (CONTINUE) Tj (:) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# update arguments) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj (args) Tj (,) Tj ( ) Tj (kwd) Tj ( ) 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 T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (else) Tj /F4 10 Tf 0 0 0 rg (:) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# last call) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (result) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (finally) Tj /F4 10 Tf 0 0 0 rg (:) Tj T* ( ) Tj 0 .501961 0 rg (self) Tj .4 .4 .4 rg (.) Tj 0 0 0 rg (firstcall) Tj ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj 0 .501961 0 rg (True) Tj 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (else) Tj /F4 10 Tf 0 0 0 rg (:) Tj ( ) Tj /F6 10 Tf .25098 .501961 .501961 rg (# return the arguments of the tail call) Tj /F4 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 ( ) Tj .4 .4 .4 rg (=) Tj 0 0 0 rg ( ) Tj (args) Tj (,) Tj ( ) Tj (kwd) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (CONTINUE) Tj T* ET
Q
Q
Q
Q
Q
-
-endstream
-endobj
-% 'R97': class PDFStream
-97 0 obj
-% page stream
-<< /Length 5346 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
-q
-1 0 0 1 62.69291 739.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 24 re B*
-Q
-q
-BT 1 0 0 1 0 2 Tm 12 TL /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (CONTINUE) Tj T* ET
-Q
-Q
-Q
-Q
-Q
-q
-1 0 0 1 62.69291 719.8236 cm
+1 0 0 1 62.69291 285.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 674.6236 cm
+1 0 0 1 62.69291 240.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -3227,14 +3369,14 @@ Q
Q
Q
q
-1 0 0 1 62.69291 654.6236 cm
+1 0 0 1 62.69291 220.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 573.4236 cm
+1 0 0 1 62.69291 139.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -3254,7 +3396,7 @@ Q
Q
Q
q
-1 0 0 1 62.69291 528.2236 cm
+1 0 0 1 62.69291 94.22362 cm
q
q
1 0 0 1 0 0 cm
@@ -3273,14 +3415,23 @@ Q
Q
Q
Q
+
+endstream
+endobj
+% 'R101': class PDFStream
+101 0 obj
+% page stream
+<< /Length 4932 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 472.2236 cm
+1 0 0 1 62.69291 717.0236 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 /F4 10 Tf (factorial\(1001\) ) Tj /F1 10 Tf (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 415.0236 cm
+1 0 0 1 62.69291 659.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -3300,27 +3451,27 @@ Q
Q
Q
q
-1 0 0 1 62.69291 383.0236 cm
+1 0 0 1 62.69291 627.8236 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 350.0236 cm
+1 0 0 1 62.69291 594.8236 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 320.0236 cm
+1 0 0 1 62.69291 564.8236 cm
q
0 0 0 rg
BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .474987 Tw (The first thing you should be aware of, it the fact that decorators have a performance penalty. The worse) Tj T* 0 Tw (case is shown by the following example:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 94.82362 cm
+1 0 0 1 62.69291 339.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -3340,23 +3491,14 @@ Q
Q
Q
Q
-
-endstream
-endobj
-% 'R98': class PDFStream
-98 0 obj
-% page stream
-<< /Length 7413 >>
-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
+1 0 0 1 62.69291 307.6236 cm
q
BT 1 0 0 1 0 14 Tm .266235 Tw 12 TL /F1 10 Tf 0 0 0 rg (On my MacBook, using the ) Tj /F4 10 Tf (do_nothing ) Tj /F1 10 Tf (decorator instead of the plain function is more than three times) Tj T* 0 Tw (slower:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 683.8236 cm
+1 0 0 1 62.69291 250.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -3377,20 +3519,20 @@ Q
Q
Q
q
-1 0 0 1 62.69291 639.8236 cm
+1 0 0 1 62.69291 206.4236 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 /F4 10 Tf (f ) Tj /F1 10 Tf (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 609.8236 cm
+1 0 0 1 62.69291 176.4236 cm
q
0 0 0 rg
BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .867984 Tw (You should be aware that decorators will make your tracebacks longer and more difficult to understand.) Tj T* 0 Tw (Consider this example:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 552.6236 cm
+1 0 0 1 62.69291 119.2236 cm
q
q
1 0 0 1 0 0 cm
@@ -3410,13 +3552,22 @@ Q
Q
Q
q
-1 0 0 1 62.69291 520.6236 cm
+1 0 0 1 62.69291 87.22362 cm
q
BT 1 0 0 1 0 14 Tm .583318 Tw 12 TL /F1 10 Tf 0 0 0 rg (Calling ) Tj /F4 10 Tf (f\(\) ) Tj /F1 10 Tf (will give you a ) Tj /F4 10 Tf (ZeroDivisionError) Tj /F1 10 Tf (, but since the function is decorated the traceback will) Tj T* 0 Tw (be longer:) Tj T* ET
Q
Q
+
+endstream
+endobj
+% 'R102': class PDFStream
+102 0 obj
+% page stream
+<< /Length 8009 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 391.4236 cm
+1 0 0 1 62.69291 643.8236 cm
q
q
1 0 0 1 0 0 cm
@@ -3436,60 +3587,31 @@ Q
Q
Q
q
-1 0 0 1 62.69291 323.4236 cm
+1 0 0 1 62.69291 575.8236 cm
q
-BT 1 0 0 1 0 50 Tm 1.05528 Tw 12 TL /F1 10 Tf 0 0 0 rg (You see here the inner call to the decorator ) Tj /F4 10 Tf (trace) Tj /F1 10 Tf (, which calls ) Tj /F4 10 Tf (f\(*args, **kw\)) Tj /F1 10 Tf (, and a reference to) Tj T* 0 Tw .265868 Tw /F4 10 Tf (File ") Tj (<) Tj (string) Tj (>) Tj (", line 2, in f) Tj /F1 10 Tf (. This latter reference is due to the fact that internally the decorator) Tj T* 0 Tw 2.053318 Tw (module uses ) Tj /F4 10 Tf (exec ) Tj /F1 10 Tf (to generate the decorated function. Notice that ) Tj /F4 10 Tf (exec ) Tj /F1 10 Tf (is ) Tj /F5 10 Tf (not ) Tj /F1 10 Tf (responsibile for the) Tj T* 0 Tw 1.507485 Tw (performance penalty, since is the called ) Tj /F5 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
+BT 1 0 0 1 0 50 Tm 1.05528 Tw 12 TL /F1 10 Tf 0 0 0 rg (You see here the inner call to the decorator ) Tj /F4 10 Tf (trace) Tj /F1 10 Tf (, which calls ) Tj /F4 10 Tf (f\(*args,) Tj ( ) Tj (**kw\)) Tj /F1 10 Tf (, and a reference to) Tj T* 0 Tw .076457 Tw /F4 10 Tf (File) Tj ( ) Tj (") Tj (<) Tj (string) Tj (>) Tj (",) Tj ( ) Tj (line) Tj ( ) Tj (2,) Tj ( ) Tj (in) Tj ( ) Tj (f) Tj /F1 10 Tf (. This latter reference is due to the fact that internally the decorator) Tj T* 0 Tw 2.053318 Tw (module uses ) Tj /F4 10 Tf (exec ) Tj /F1 10 Tf (to generate the decorated function. Notice that ) Tj /F4 10 Tf (exec ) Tj /F1 10 Tf (is ) Tj /F5 10 Tf (not ) Tj /F1 10 Tf (responsibile for the) Tj T* 0 Tw 1.507485 Tw (performance penalty, since is the called ) Tj /F5 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 245.4236 cm
+1 0 0 1 62.69291 497.8236 cm
q
-BT 1 0 0 1 0 62 Tm .932209 Tw 12 TL /F1 10 Tf 0 0 0 rg (At present, there is no clean way to avoid ) Tj /F4 10 Tf (exec) Tj /F1 10 Tf (. A clean solution would require to change the CPython) Tj T* 0 Tw .777485 Tw (implementation of functions and add an hook to make it possible to change their signature directly. That) Tj T* 0 Tw .74186 Tw (could happen in future versions of Python \(see PEP ) Tj 0 0 .501961 rg (362) Tj 0 0 0 rg (\) and then the decorator module would become) Tj T* 0 Tw 2.385318 Tw (obsolete. However, at present, even in Python 3.1 it is impossible to change the function signature) Tj T* 0 Tw .931751 Tw (directly, therefore the ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (module is still useful. Actually, this is one of the main reasons why I) Tj T* 0 Tw (keep maintaining the module and releasing new versions.) Tj T* ET
+BT 1 0 0 1 0 62 Tm .932209 Tw 12 TL /F1 10 Tf 0 0 0 rg (At present, there is no clean way to avoid ) Tj /F4 10 Tf (exec) Tj /F1 10 Tf (. A clean solution would require to change the CPython) Tj T* 0 Tw .777485 Tw (implementation of functions and add an hook to make it possible to change their signature directly. That) Tj T* 0 Tw .74186 Tw (could happen in future versions of Python \(see PEP ) Tj 0 0 .501961 rg (362) Tj 0 0 0 rg (\) and then the decorator module would become) Tj T* 0 Tw 2.385318 Tw (obsolete. However, at present, even in Python 3.2 it is impossible to change the function signature) Tj T* 0 Tw .931751 Tw (directly, therefore the ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (module is still useful. Actually, this is one of the main reasons why I) Tj T* 0 Tw (keep maintaining the module and releasing new versions.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 203.4236 cm
+1 0 0 1 62.69291 455.8236 cm
q
BT 1 0 0 1 0 26 Tm 1.043828 Tw 12 TL /F1 10 Tf 0 0 0 rg (In the present implementation, decorators generated by ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (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 (the ) Tj /F4 10 Tf (inspect ) Tj /F1 10 Tf (module in the standard library.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 173.4236 cm
+1 0 0 1 62.69291 425.8236 cm
q
BT 1 0 0 1 0 14 Tm .785777 Tw 12 TL /F1 10 Tf 0 0 0 rg (There is a restriction on the names of the arguments: for instance, if try to call an argument ) Tj /F4 10 Tf (_call_ ) Tj /F1 10 Tf (or) Tj T* 0 Tw /F4 10 Tf (_func_ ) Tj /F1 10 Tf (you will get a ) Tj /F4 10 Tf (NameError) Tj /F1 10 Tf (:) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 80.22362 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
-BT 1 0 0 1 0 62 Tm 12 TL /F4 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 /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (f) Tj 0 0 0 rg (\() Tj (_func_) Tj (\):) Tj ( ) Tj /F3 10 Tf 0 .501961 0 rg (print) Tj /F4 10 Tf 0 0 0 rg (\() Tj (f) Tj (\)) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg T* (Traceback) Tj ( ) Tj (\() Tj (most) Tj ( ) Tj (recent) Tj ( ) Tj (call) Tj ( ) Tj (last) Tj (\):) Tj T* ( ) Tj .4 .4 .4 rg (...) Tj 0 0 0 rg T* /F3 10 Tf .823529 .254902 .227451 rg (NameError) Tj /F4 10 Tf 0 0 0 rg (:) Tj ( ) Tj (_func_) Tj ( ) Tj /F3 10 Tf .666667 .133333 1 rg (is) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (overridden) Tj ( ) Tj /F3 10 Tf .666667 .133333 1 rg (in) Tj /F4 10 Tf 0 0 0 rg T* ET
-Q
-Q
-Q
-Q
-Q
-
-endstream
-endobj
-% 'R99': class PDFStream
-99 0 obj
-% page stream
-<< /Length 7419 >>
-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
+1 0 0 1 62.69291 308.6236 cm
q
q
1 0 0 1 0 0 cm
@@ -3499,23 +3621,23 @@ q
.662745 .662745 .662745 RG
.5 w
.960784 .960784 .862745 rg
-n -6 -6 468.6898 36 re B*
+n -6 -6 468.6898 108 re B*
Q
q
-BT 1 0 0 1 0 14 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (f) Tj 0 0 0 rg (\() Tj (_func_) Tj (\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (_call_) Tj (\() Tj (_func_) Tj (,) Tj ( ) Tj (_func_) Tj (\)) Tj T* ET
+BT 1 0 0 1 0 86 Tm 12 TL /F4 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 /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (f) Tj 0 0 0 rg (\() Tj (_func_) Tj (\):) Tj ( ) Tj /F3 10 Tf 0 .501961 0 rg (print) Tj /F4 10 Tf 0 0 0 rg (\() Tj (f) Tj (\)) Tj T* .4 .4 .4 rg (...) Tj 0 0 0 rg T* (Traceback) Tj ( ) Tj (\() Tj (most) Tj ( ) Tj (recent) Tj ( ) Tj (call) Tj ( ) Tj (last) Tj (\):) Tj T* ( ) Tj .4 .4 .4 rg (...) Tj 0 0 0 rg T* /F3 10 Tf .823529 .254902 .227451 rg (NameError) Tj /F4 10 Tf 0 0 0 rg (:) Tj ( ) Tj (_func_) Tj ( ) Tj /F3 10 Tf .666667 .133333 1 rg (is) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (overridden) Tj ( ) Tj /F3 10 Tf .666667 .133333 1 rg (in) Tj /F4 10 Tf 0 0 0 rg T* /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (f) Tj 0 0 0 rg (\() Tj (_func_) Tj (\):) Tj T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj (_call_) Tj (\() Tj (_func_) Tj (,) Tj ( ) Tj (_func_) Tj (\)) Tj T* ET
Q
Q
Q
Q
Q
q
-1 0 0 1 62.69291 695.8236 cm
+1 0 0 1 62.69291 276.6236 cm
q
-BT 1 0 0 1 0 14 Tm 1.533318 Tw 12 TL /F1 10 Tf 0 0 0 rg (Finally, the implementation is such that the decorated function contains a ) Tj /F5 10 Tf (copy ) Tj /F1 10 Tf (of the original function) Tj T* 0 Tw (dictionary \() Tj /F4 10 Tf (vars\(decorated_f\) is not vars\(f\)) Tj /F1 10 Tf (\):) Tj T* ET
+BT 1 0 0 1 0 14 Tm 1.533318 Tw 12 TL /F1 10 Tf 0 0 0 rg (Finally, the implementation is such that the decorated function contains a ) Tj /F5 10 Tf (copy ) Tj /F1 10 Tf (of the original function) Tj T* 0 Tw (dictionary \() Tj /F4 10 Tf (vars\(decorated_f\)) Tj ( ) Tj (is) Tj ( ) Tj (not) Tj ( ) Tj (vars\(f\)) Tj /F1 10 Tf (\):) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 542.6236 cm
+1 0 0 1 62.69291 123.4236 cm
q
q
1 0 0 1 0 0 cm
@@ -3534,76 +3656,76 @@ Q
Q
Q
Q
+
+endstream
+endobj
+% 'R103': class PDFStream
+103 0 obj
+% page stream
+<< /Length 6552 >>
+stream
+1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 509.6236 cm
+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 (Compatibility notes) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 443.6236 cm
+1 0 0 1 62.69291 678.0236 cm
q
BT 1 0 0 1 0 50 Tm 1.404985 Tw 12 TL /F1 10 Tf 0 0 0 rg (Version 3.3 is the first version of the ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (module to fully support Python 3, including ) Tj 0 0 .501961 rg (function) Tj T* 0 Tw .07881 Tw (annotations) Tj 0 0 0 rg (. Version 3.2 was the first version to support Python 3 via the ) Tj /F4 10 Tf (2to3 ) Tj /F1 10 Tf (conversion tool invoked in) Tj T* 0 Tw .373555 Tw (the build process by the ) Tj 0 0 .501961 rg (distribute ) Tj 0 0 0 rg (project, the Python 3-compatible replacement of easy_install. The hard) Tj T* 0 Tw .326235 Tw (work \(for me\) has been converting the documentation and the doctests. This has been possible only after) Tj T* 0 Tw (that ) Tj 0 0 .501961 rg (docutils ) Tj 0 0 0 rg (and ) Tj 0 0 .501961 rg (pygments ) Tj 0 0 0 rg (have been ported to Python 3.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 365.6236 cm
+1 0 0 1 62.69291 600.0236 cm
q
BT 1 0 0 1 0 62 Tm .793984 Tw 12 TL /F1 10 Tf 0 0 0 rg (Version 3 of the ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (module do not contain any backward incompatible change, apart from the) Tj T* 0 Tw 3.63498 Tw (removal of the functions ) Tj /F4 10 Tf (get_info ) Tj /F1 10 Tf (and ) Tj /F4 10 Tf (new_wrapper) Tj /F1 10 Tf (, which have been deprecated for years.) Tj T* 0 Tw .293672 Tw /F4 10 Tf (get_info ) Tj /F1 10 Tf (has been removed since it was little used and since it had to be changed anyway to work with) Tj T* 0 Tw 2.298555 Tw (Python 3.0; ) Tj /F4 10 Tf (new_wrapper ) Tj /F1 10 Tf (has been removed since it was useless: its major use case \(converting) Tj T* 0 Tw 7.136976 Tw (signature changing decorators to signature preserving decorators\) has been subsumed by) Tj T* 0 Tw /F4 10 Tf (decorator_apply) Tj /F1 10 Tf (, whereas the other use case can be managed with the ) Tj /F4 10 Tf (FunctionMaker) Tj /F1 10 Tf (.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 323.6236 cm
+1 0 0 1 62.69291 558.0236 cm
q
BT 1 0 0 1 0 26 Tm 1.329213 Tw 12 TL /F1 10 Tf 0 0 0 rg (There are a few changes in the documentation: I removed the ) Tj /F4 10 Tf (decorator_factory ) Tj /F1 10 Tf (example, which) Tj T* 0 Tw 2.562927 Tw (was confusing some of my users, and I removed the part about exotic signatures in the Python 3) Tj T* 0 Tw (documentation, since Python 3 does not support them.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 257.6236 cm
+1 0 0 1 62.69291 492.0236 cm
q
BT 1 0 0 1 0 50 Tm .942651 Tw 12 TL /F1 10 Tf 0 0 0 rg (Finally ) Tj /F4 10 Tf (decorator ) Tj /F1 10 Tf (cannot be used as a class decorator and the ) Tj 0 0 .501961 rg (functionality introduced in version 2.3) Tj T* 0 Tw .241163 Tw 0 0 0 rg (has been removed. That means that in order to define decorator factories with classes you need to define) Tj T* 0 Tw 1.122126 Tw (the ) Tj /F4 10 Tf (__call__ ) Tj /F1 10 Tf (method explicitly \(no magic anymore\). All these changes should not cause any trouble,) Tj T* 0 Tw .601163 Tw (since they were all rarely used features. Should you have any trouble, you can always downgrade to the) Tj T* 0 Tw (2.3 version.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 191.6236 cm
+1 0 0 1 62.69291 426.0236 cm
q
BT 1 0 0 1 0 50 Tm .196098 Tw 12 TL /F1 10 Tf 0 0 0 rg (The examples shown here have been tested with Python 2.6. Python 2.4 is also supported - of course the) Tj T* 0 Tw 1.649398 Tw (examples requiring the ) Tj /F4 10 Tf (with ) Tj /F1 10 Tf (statement will not work there. Python 2.5 works fine, but if you run the) Tj T* 0 Tw 1.41784 Tw (examples in the interactive interpreter you will notice a few differences since ) Tj /F4 10 Tf (getargspec ) Tj /F1 10 Tf (returns an) Tj T* 0 Tw .909982 Tw /F4 10 Tf (ArgSpec ) Tj /F1 10 Tf (namedtuple instead of a regular tuple. That means that running the file ) Tj /F4 10 Tf (documentation.py) Tj T* 0 Tw /F1 10 Tf (under Python 2.5 will print a few errors, but they are not serious.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 158.6236 cm
+1 0 0 1 62.69291 393.0236 cm
q
BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (LICENCE) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 140.6236 cm
+1 0 0 1 62.69291 375.0236 cm
q
0 0 0 rg
BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Copyright \(c\) 2005-2012, Michele Simionato All rights reserved.) Tj T* ET
Q
Q
q
-1 0 0 1 62.69291 110.6236 cm
+1 0 0 1 62.69291 345.0236 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 104.6236 cm
+1 0 0 1 62.69291 339.0236 cm
Q
-
-endstream
-endobj
-% 'R100': class PDFStream
-100 0 obj
-% page stream
-<< /Length 2070 >>
-stream
-1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
q
-1 0 0 1 62.69291 717.0236 cm
+1 0 0 1 62.69291 291.0236 cm
0 0 0 rg
BT /F1 10 Tf 12 TL ET
BT 1 0 0 1 0 2 Tm T* ET
@@ -3618,17 +3740,17 @@ q
Q
Q
q
-1 0 0 1 62.69291 717.0236 cm
+1 0 0 1 62.69291 291.0236 cm
Q
q
-1 0 0 1 62.69291 591.0236 cm
+1 0 0 1 62.69291 165.0236 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 561.0236 cm
+1 0 0 1 62.69291 135.0236 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
@@ -3637,132 +3759,132 @@ Q
endstream
endobj
-% 'R101': class PDFPageLabels
-101 0 obj
+% 'R104': class PDFPageLabels
+104 0 obj
% Document Root
<< /Nums [ 0
- 102 0 R
+ 105 0 R
1
- 103 0 R
+ 106 0 R
2
- 104 0 R
+ 107 0 R
3
- 105 0 R
+ 108 0 R
4
- 106 0 R
+ 109 0 R
5
- 107 0 R
+ 110 0 R
6
- 108 0 R
+ 111 0 R
7
- 109 0 R
+ 112 0 R
8
- 110 0 R
+ 113 0 R
9
- 111 0 R
+ 114 0 R
10
- 112 0 R
+ 115 0 R
11
- 113 0 R
+ 116 0 R
12
- 114 0 R
+ 117 0 R
13
- 115 0 R
+ 118 0 R
14
- 116 0 R ] >>
-endobj
-% 'R102': class PDFPageLabel
-102 0 obj
-% None
-<< /S /D
- /St 1 >>
-endobj
-% 'R103': class PDFPageLabel
-103 0 obj
-% None
-<< /S /D
- /St 2 >>
-endobj
-% 'R104': class PDFPageLabel
-104 0 obj
-% None
-<< /S /D
- /St 3 >>
+ 119 0 R ] >>
endobj
% 'R105': class PDFPageLabel
105 0 obj
% None
<< /S /D
- /St 4 >>
+ /St 1 >>
endobj
% 'R106': class PDFPageLabel
106 0 obj
% None
<< /S /D
- /St 5 >>
+ /St 2 >>
endobj
% 'R107': class PDFPageLabel
107 0 obj
% None
<< /S /D
- /St 6 >>
+ /St 3 >>
endobj
% 'R108': class PDFPageLabel
108 0 obj
% None
<< /S /D
- /St 7 >>
+ /St 4 >>
endobj
% 'R109': class PDFPageLabel
109 0 obj
% None
<< /S /D
- /St 8 >>
+ /St 5 >>
endobj
% 'R110': class PDFPageLabel
110 0 obj
% None
<< /S /D
- /St 9 >>
+ /St 6 >>
endobj
% 'R111': class PDFPageLabel
111 0 obj
% None
<< /S /D
- /St 10 >>
+ /St 7 >>
endobj
% 'R112': class PDFPageLabel
112 0 obj
% None
<< /S /D
- /St 11 >>
+ /St 8 >>
endobj
% 'R113': class PDFPageLabel
113 0 obj
% None
<< /S /D
- /St 12 >>
+ /St 9 >>
endobj
% 'R114': class PDFPageLabel
114 0 obj
% None
<< /S /D
- /St 13 >>
+ /St 10 >>
endobj
% 'R115': class PDFPageLabel
115 0 obj
% None
<< /S /D
- /St 14 >>
+ /St 11 >>
endobj
% 'R116': class PDFPageLabel
116 0 obj
% None
<< /S /D
+ /St 12 >>
+endobj
+% 'R117': class PDFPageLabel
+117 0 obj
+% None
+<< /S /D
+ /St 13 >>
+endobj
+% 'R118': class PDFPageLabel
+118 0 obj
+% None
+<< /S /D
+ /St 14 >>
+endobj
+% 'R119': class PDFPageLabel
+119 0 obj
+% None
+<< /S /D
/St 15 >>
endobj
xref
-0 117
+0 120
0000000000 65535 f
0000000113 00000 n
0000000271 00000 n
@@ -3801,93 +3923,96 @@ xref
0000008020 00000 n
0000008263 00000 n
0000008506 00000 n
-0000008733 00000 n
-0000009311 00000 n
-0000009506 00000 n
-0000009762 00000 n
-0000009953 00000 n
-0000010213 00000 n
-0000010523 00000 n
-0000010803 00000 n
-0000011098 00000 n
-0000011341 00000 n
-0000011642 00000 n
-0000011922 00000 n
-0000012202 00000 n
-0000012482 00000 n
-0000012777 00000 n
-0000013018 00000 n
-0000013334 00000 n
-0000013602 00000 n
-0000013904 00000 n
-0000014199 00000 n
-0000014444 00000 n
-0000014760 00000 n
-0000015020 00000 n
-0000015280 00000 n
-0000015538 00000 n
-0000015790 00000 n
-0000016030 00000 n
-0000016337 00000 n
-0000016684 00000 n
-0000016966 00000 n
-0000017126 00000 n
-0000017411 00000 n
-0000017537 00000 n
-0000017710 00000 n
-0000017897 00000 n
-0000018097 00000 n
-0000018285 00000 n
-0000018478 00000 n
-0000018673 00000 n
-0000018873 00000 n
-0000019057 00000 n
-0000019238 00000 n
-0000019438 00000 n
-0000019638 00000 n
-0000019850 00000 n
-0000020050 00000 n
-0000020246 00000 n
-0000020398 00000 n
-0000020633 00000 n
-0000029773 00000 n
-0000037418 00000 n
-0000045484 00000 n
-0000052710 00000 n
-0000060998 00000 n
-0000069460 00000 n
-0000076522 00000 n
-0000083856 00000 n
-0000091630 00000 n
-0000098966 00000 n
-0000106444 00000 n
-0000111889 00000 n
-0000119401 00000 n
-0000126920 00000 n
-0000129095 00000 n
-0000129392 00000 n
-0000129471 00000 n
-0000129550 00000 n
-0000129629 00000 n
-0000129708 00000 n
-0000129787 00000 n
-0000129866 00000 n
-0000129945 00000 n
-0000130024 00000 n
-0000130103 00000 n
-0000130183 00000 n
-0000130263 00000 n
-0000130343 00000 n
-0000130423 00000 n
-0000130503 00000 n
+0000008749 00000 n
+0000008992 00000 n
+0000009219 00000 n
+0000009815 00000 n
+0000010010 00000 n
+0000010266 00000 n
+0000010457 00000 n
+0000010717 00000 n
+0000011027 00000 n
+0000011307 00000 n
+0000011602 00000 n
+0000011845 00000 n
+0000012146 00000 n
+0000012426 00000 n
+0000012706 00000 n
+0000012986 00000 n
+0000013267 00000 n
+0000013562 00000 n
+0000013803 00000 n
+0000014119 00000 n
+0000014387 00000 n
+0000014690 00000 n
+0000014986 00000 n
+0000015231 00000 n
+0000015548 00000 n
+0000015808 00000 n
+0000016068 00000 n
+0000016326 00000 n
+0000016578 00000 n
+0000016818 00000 n
+0000017125 00000 n
+0000017473 00000 n
+0000017633 00000 n
+0000017918 00000 n
+0000018044 00000 n
+0000018217 00000 n
+0000018404 00000 n
+0000018604 00000 n
+0000018792 00000 n
+0000018985 00000 n
+0000019180 00000 n
+0000019380 00000 n
+0000019564 00000 n
+0000019745 00000 n
+0000019936 00000 n
+0000020136 00000 n
+0000020336 00000 n
+0000020548 00000 n
+0000020748 00000 n
+0000020944 00000 n
+0000021096 00000 n
+0000021331 00000 n
+0000030688 00000 n
+0000038447 00000 n
+0000046641 00000 n
+0000054544 00000 n
+0000062233 00000 n
+0000071127 00000 n
+0000077895 00000 n
+0000086065 00000 n
+0000093096 00000 n
+0000101341 00000 n
+0000108766 00000 n
+0000116365 00000 n
+0000121398 00000 n
+0000129508 00000 n
+0000136165 00000 n
+0000136462 00000 n
+0000136541 00000 n
+0000136620 00000 n
+0000136699 00000 n
+0000136778 00000 n
+0000136857 00000 n
+0000136936 00000 n
+0000137015 00000 n
+0000137094 00000 n
+0000137173 00000 n
+0000137253 00000 n
+0000137333 00000 n
+0000137413 00000 n
+0000137493 00000 n
+0000137573 00000 n
trailer
<< /ID
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
- [(ZF\355\316\224\\\024M~FN\227KUr\335) (ZF\355\316\224\\\024M~FN\227KUr\335)]
+ [(GkM\035\327P\251\240\010\276P *\252E\027) (GkM\035\327P\251\240\010\276P *\252E\027)]
- /Info 68 0 R
- /Root 67 0 R
- /Size 117 >>
+ /Info 70 0 R
+ /Root 69 0 R
+ /Size 120 >>
startxref
-130552
+137622
%%EOF
diff --git a/decorator/documentation3.py b/decorator/documentation3.py
index 07a4e40..bd86cc6 100644
--- a/decorator/documentation3.py
+++ b/decorator/documentation3.py
@@ -130,7 +130,7 @@ argument, you will get an error:
.. code-block:: python
- >>> f1(0, 1)
+ >>> f1(0, 1) # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
TypeError: f1() takes exactly 1 positional argument (2 given)
@@ -302,7 +302,8 @@ For instance, you can write directly
>>> @decorator
... def trace(f, *args, **kw):
- ... print("calling %s with args %s, %s" % (f.__name__, 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. Actually ``trace`` is a ``partial``
@@ -370,18 +371,16 @@ We have just seen an examples of a simple decorator factory,
implemented as a function returning a decorator.
For more complex situations, it is more
convenient to implement decorator factories as classes returning
-callable objects that can be used as signature-preserving
-decorators. The suggested pattern to do that is to introduce
-a helper method ``call(self, func, *args, **kw)`` and to call
-it in the ``__call__(self, func)`` method.
+callable objects that can be converted into decorators.
-As an example, here I show a decorator
+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. Moreover, it is possible to set
three callbacks ``on_success``, ``on_failure`` and ``on_closing``,
-to specify how to manage the function call.
-The implementation is the following:
+to specify how to manage the function call (of course the code here
+is just an example, it is not a recommended way of doing multi-threaded
+programming). The implementation is the following:
$$on_success
$$on_failure
@@ -399,7 +398,7 @@ be locked. Here is a minimalistic example:
.. code-block:: python
- >>> async = Async(threading.Thread)
+ >>> async = decorator(Async(threading.Thread))
>>> datalist = [] # for simplicity the written data are stored into a list.
@@ -429,6 +428,71 @@ be no synchronization problems since ``write`` is locked.
>>> print(datalist)
['data1', 'data2']
+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
+
+ >>> ba = before_after('BEFORE', 'AFTER')
+ >>> type(ba)
+ <class 'contextlib._GeneratorContextManager'>
+ >>> with ba:
+ ... 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; 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 even in Python 2.5.
+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
---------------------------------------------------------------
@@ -832,7 +896,8 @@ def decorator_apply(dec, func):
dict(decorated=dec(func)), __wrapped__=func)
def _trace(f, *args, **kw):
- print("calling %s with args %s, %s" % (f.__name__, 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):
@@ -859,29 +924,28 @@ class Async(object):
async_with_processes = Async(multiprocessing.Process)
"""
- def __init__(self, threadfactory):
- self.threadfactory = threadfactory
-
- def __call__(self, func, on_success=on_success,
+ def __init__(self, threadfactory, on_success=on_success,
on_failure=on_failure, on_closing=on_closing):
- # every decorated function has its own independent thread counter
- func.counter = itertools.count(1)
- func.on_success = on_success
- func.on_failure = on_failure
- func.on_closing = on_closing
- return decorator(self.call, func)
-
- def call(self, func, *args, **kw):
+ self.threadfactory = threadfactory
+ self.on_success = on_success
+ self.on_failure = on_failure
+ self.on_closing = on_closing
+
+ def __call__(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():
try:
result = func(*args, **kw)
except:
- func.on_failure(sys.exc_info())
+ self.on_failure(sys.exc_info())
else:
- return func.on_success(result)
+ return self.on_success(result)
finally:
- func.on_closing()
- name = '%s-%s' % (func.__name__, next(func.counter))
+ self.on_closing()
thread = self.threadfactory(None, func_wrapper, name)
thread.start()
return thread
@@ -1039,7 +1103,7 @@ def a_test_for_pylons():
>>> decorator(_memoize).__name__
'_memoize'
- Here is another bug of version 3.1.1 missing the docstring to avoid:
+ Here is another bug of version 3.1.1 missing the docstring:
>>> factorial.__doc__
'The good old factorial'
@@ -1061,9 +1125,46 @@ def test_kwonlyargs():
... return y, z
...
>>> func('a', 'b', 'c', 'd', 'e', y='y', z='z', cat='dog')
- calling func with args ('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
+ ...
+ >>> 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)
+
if __name__ == '__main__':
import doctest; doctest.testmod()
diff --git a/decorator/index.html b/decorator/index.html
index b32097c..d7ab764 100644
--- a/decorator/index.html
+++ b/decorator/index.html
@@ -3,14 +3,14 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="generator" content="Docutils 0.7: http://docutils.sourceforge.net/" />
+<meta name="generator" content="Docutils 0.8.1: http://docutils.sourceforge.net/" />
<title>Decorator module</title>
<meta name="author" content="Michele Simionato" />
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
-:Id: $Id: html4css1.css 6253 2010-03-02 00:24:53Z milde $
+:Id: $Id: html4css1.css 7056 2011-06-17 10:50:48Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
@@ -48,6 +48,10 @@ blockquote.epigraph {
dl.docutils dd {
margin-bottom: 0.5em }
+object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
+ overflow: hidden;
+}
+
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
@@ -186,7 +190,7 @@ img.align-center, .figure.align-center, object.align-center {
/* reset inner alignment in figures */
div.align-right {
- text-align: left }
+ text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
@@ -246,7 +250,7 @@ pre.address {
margin-top: 0 ;
font: inherit }
-pre.literal-block, pre.doctest-block {
+pre.literal-block, pre.doctest-block, pre.math {
margin-left: 2em ;
margin-right: 2em }
diff --git a/decorator/src/decorator.py b/decorator/src/decorator.py
index 3dbbdd4..e003914 100644
--- a/decorator/src/decorator.py
+++ b/decorator/src/decorator.py
@@ -32,28 +32,15 @@ Decorator module, see http://pypi.python.org/pypi/decorator
for the documentation.
"""
-__version__ = '3.3.3'
+__version__ = '3.4.0'
-__all__ = ["decorator", "FunctionMaker", "partial"]
+__all__ = ["decorator", "FunctionMaker", "contextmanager"]
import sys, re, inspect
-
-try:
- from functools import partial
-except ImportError: # for Python version < 2.5
- class partial(object):
- "A simple replacement of functools.partial"
- def __init__(self, func, *args, **kw):
- self.func = func
- self.args = args
- self.keywords = kw
- def __call__(self, *otherargs, **otherkw):
- kw = self.keywords.copy()
- kw.update(otherkw)
- return self.func(*(self.args + otherargs), **kw)
-
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"
@@ -67,6 +54,8 @@ else:
yield self.varargs
yield self.varkw
yield self.defaults
+ def get_init(cls):
+ return cls.__init__.im_func
DEF = re.compile('\s*def\s*([_\w][_\w\d]*)\s*\(')
@@ -100,17 +89,21 @@ class FunctionMaker(object):
inspect.formatargspec(
formatvalue=lambda val: "", *argspec)[1:-1]
else: # Python 3 way
- self.signature = self.shortsignature = ', '.join(self.args)
+ allargs = list(self.args)
+ allshortargs = list(self.args)
if self.varargs:
- self.signature += ', *' + self.varargs
- self.shortsignature += ', *' + self.varargs
- if self.kwonlyargs:
- for a in self.kwonlyargs:
- self.signature += ', %s=None' % a
- self.shortsignature += ', %s=%s' % (a, a)
+ 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:
- self.signature += ', **' + self.varkw
- self.shortsignature += ', **' + 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:
@@ -206,15 +199,53 @@ def decorator(caller, func=None):
func, "return _call_(_func_, %(shortsignature)s)",
evaldict, undecorated=func, __wrapped__=func)
else: # returns a decorator
- if isinstance(caller, partial):
- return partial(decorator, caller)
- # otherwise assume caller is a function
- first = inspect.getargspec(caller)[0][0] # first arg
- evaldict = caller.func_globals.copy()
+ if inspect.isclass(caller):
+ name = caller.__name__.lower()
+ callerfunc = get_init(caller)
+ doc = 'decorator(%s) converts functions/generators into ' \
+ 'factories of %s objects' % (caller.__name__, caller.__name__)
+ fun = getfullargspec(callerfunc).args[1] # second arg
+ elif inspect.isfunction(caller):
+ name = '_lambda_' if caller.__name__ == '<lambda>' \
+ else caller.__name__
+ callerfunc = caller
+ doc = caller.__doc__
+ fun = getfullargspec(callerfunc).args[0] # first arg
+ else: # assume caller is an object with a __call__ method
+ name = caller.__class__.__name__.lower()
+ callerfunc = caller.__call__.im_func
+ doc = caller.__call__.__doc__
+ fun = getfullargspec(callerfunc).args[1] # second arg
+ evaldict = callerfunc.func_globals.copy()
evaldict['_call_'] = caller
evaldict['decorator'] = decorator
return FunctionMaker.create(
- '%s(%s)' % (caller.__name__, first),
- 'return decorator(_call_, %s)' % first,
+ '%s(%s)' % (name, fun),
+ 'return decorator(_call_, %s)' % fun,
evaldict, undecorated=caller, __wrapped__=caller,
- doc=caller.__doc__, module=caller.__module__)
+ doc=doc, module=caller.__module__)
+
+######################### contextmanager ########################
+
+def __call__(self, func):
+ 'Context manager decorator'
+ return FunctionMaker.create(
+ func, "with _self_: return _func_(%(shortsignature)s)",
+ dict(_self_=self, _func_=func), __wrapped__=func)
+
+try: # Python >= 3.2
+
+ from contextlib import _GeneratorContextManager
+ ContextManager = type(
+ 'ContextManager', (_GeneratorContextManager,), dict(__call__=__call__))
+
+except ImportError: # Python >= 2.5
+
+ from contextlib import GeneratorContextManager
+ def __init__(self, f, *a, **k):
+ return GeneratorContextManager.__init__(self, f(*a, **k))
+ ContextManager = type(
+ 'ContextManager', (GeneratorContextManager,),
+ dict(__call__=__call__, __init__=__init__))
+
+contextmanager = decorator(ContextManager)