# HG changeset patch # User Armin Rigo <arigo@tunes.org> # Date 1431666778 -7200 # Fri May 15 07:12:58 2015 +0200 # Branch extradoc # Node ID e025a5c83f2c3b0c91f1e0044b331f7aab0f1b23 # Parent 999af31a7d05bf3cbd46a2e7dc6cb73ce105c16b Rewrite a bit this section to focus on the commonly-encountered issue of non-exhausted generators. Found out that they have a close() method. diff --git a/compat.html b/compat.html --- a/compat.html +++ b/compat.html @@ -106,34 +106,24 @@ <li>Pillow (the PIL fork)</li> <li><a class="reference external" href="https://github.com/amauryfa/lxml/tree/cffi/">lxml</a></li> </ul> -<p>Known differences that are not going to be fixed:</p> -<ul> -<li><p class="first">PyPy does not support refcounting semantics. The following code -won't fill the file immediately, but only after a certain period -of time, when the GC does a collection:</p> +<p>The main difference that is not going to be fixed is that PyPy does +not support refcounting semantics. The following code won't fill the +file immediately, but only after a certain period of time, when the GC +does a collection:</p> <div class="syntax python"><pre><span class="nb">open</span><span class="p">(</span><span class="s">"filename"</span><span class="p">,</span> <span class="s">"w"</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">"stuff"</span><span class="p">)</span><br/></pre></div> <p>The proper fix is</p> <div class="syntax python"><pre><span class="n">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">"filename"</span><span class="p">,</span> <span class="s">"w"</span><span class="p">)</span><br/><span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">"stuff"</span><span class="p">)</span><br/><span class="n">f</span><span class="o">.</span><span class="n">close</span><span class="p">()</span><br/></pre></div> <p>or using the <tt class="docutils literal">with</tt> keyword</p> <div class="syntax python"><pre><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"filename"</span><span class="p">,</span> <span class="s">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span><br/> <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">"stuff"</span><span class="p">)</span><br/></pre></div> -<p>See <a class="reference external" href="http://pypy.readthedocs.org/en/latest/cpython_differences.html#differences-related-to-garbage-collection-strategies">more details here</a>.</p> -</li> -<li><p class="first">For the same reason, some functions and attributes of the <tt class="docutils literal">gc</tt> module -behave in a slightly different way: for example, <tt class="docutils literal">gc.enable</tt> and -<tt class="docutils literal">gc.disable</tt> are supported, but instead of enabling and disabling the GC, -they just enable and disable the execution of finalizers. Also, -<tt class="docutils literal">gc.garbage</tt> always returns an empty list.</p> -</li> -<li><p class="first">You can't add a <tt class="docutils literal">__del__</tt> method to an existing class; it -must be present in the class since the beginning, or else it -will not be automatically called when instances are freed.</p> -</li> -<li><p class="first">You can't store non-string keys in type objects. Example</p> -<div class="syntax python"><pre><span class="k">class</span> <span class="nc">A</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span><br/> <span class="nb">locals</span><span class="p">()[</span><span class="mi">42</span><span class="p">]</span> <span class="o">=</span> <span class="mi">3</span><br/></pre></div> -<p>won't work.</p> -</li> -</ul> -<p>A more complete list is available at <a class="reference external" href="http://pypy.readthedocs.org/en/latest/cpython_differences.html">our dev site</a>.</p> +<p>Similarly, remember that you must <tt class="docutils literal">close()</tt> a non-exhausted +generator in order to have its pending <tt class="docutils literal">finally</tt> or <tt class="docutils literal">with</tt> +clauses executed immediately:</p> +<div class="syntax python"><pre><span class="k">def</span> <span class="nf">mygen</span><span class="p">():</span><br/> <span class="k">with</span> <span class="n">foo</span><span class="p">:</span><br/> <span class="k">yield</span> <span class="mi">42</span><br/><br/><span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">mygen</span><span class="p">():</span><br/> <span class="k">if</span> <span class="n">x</span> <span class="o">==</span> <span class="mi">42</span><span class="p">:</span><br/> <span class="k">break</span> <span class="c"># foo.__exit__ is not run immediately!</span><br/><br/><span class="c"># fixed version:</span><br/><span class="n">gen</span> <span class="o">=</span> <span class="n">mygen</span><span class="p">()</span><br/><span class="k">try</span><span class="p">:</span><br/> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">gen</span><span class="p">:</span><br/> <span class="k">if</span> <span class="n">x</span> <span class="o">==</span> <span class="mi">42</span><span class="p">:</span><br/> <span class="k">break</span><br/><span class="k">finally</span><span class="p">:</span><br/> <span class="n">gen</span><span class="o">.</span><span class="n">close</span><span class="p">()</span><br/></pre></div> +<p>More generally, <tt class="docutils literal">__del__()</tt> methods are not executed as predictively +as on CPython: they run “some time later” in PyPy (or not at all if +the program finishes running in the meantime). See <a class="reference external" href="http://pypy.readthedocs.org/en/latest/cpython_differences.html#differences-related-to-garbage-collection-strategies">more details +here</a>.</p> +<p>A more complete list of known differences is available at <a class="reference external" href="http://pypy.readthedocs.org/en/latest/cpython_differences.html">our dev site</a>.</p> </div> <div id="sidebar"> </div> diff --git a/source/compat.txt b/source/compat.txt --- a/source/compat.txt +++ b/source/compat.txt @@ -58,53 +58,59 @@ * `lxml`_ -Known differences that are not going to be fixed: +The main difference that is not going to be fixed is that PyPy does +not support refcounting semantics. The following code won't fill the +file immediately, but only after a certain period of time, when the GC +does a collection: -* PyPy does not support refcounting semantics. The following code - won't fill the file immediately, but only after a certain period - of time, when the GC does a collection: - - .. syntax:: python +.. syntax:: python open("filename", "w").write("stuff") - The proper fix is +The proper fix is - .. syntax:: python +.. syntax:: python f = open("filename", "w") f.write("stuff") f.close() - or using the ``with`` keyword +or using the ``with`` keyword - .. syntax:: python +.. syntax:: python with open("filename", "w") as f: f.write("stuff") - See `more details here`_. +Similarly, remember that you must ``close()`` a non-exhausted +generator in order to have its pending ``finally`` or ``with`` +clauses executed immediately: + +.. syntax:: python -* For the same reason, some functions and attributes of the ``gc`` module - behave in a slightly different way: for example, ``gc.enable`` and - ``gc.disable`` are supported, but instead of enabling and disabling the GC, - they just enable and disable the execution of finalizers. Also, - ``gc.garbage`` always returns an empty list. + def mygen(): + with foo: + yield 42 + + for x in mygen(): + if x == 42: + break # foo.__exit__ is not run immediately! -* You can't add a ``__del__`` method to an existing class; it - must be present in the class since the beginning, or else it - will not be automatically called when instances are freed. - -* You can't store non-string keys in type objects. Example + # fixed version: + gen = mygen() + try: + for x in gen: + if x == 42: + break + finally: + gen.close() - .. syntax:: python +More generally, ``__del__()`` methods are not executed as predictively +as on CPython: they run "some time later" in PyPy (or not at all if +the program finishes running in the meantime). See `more details +here`_. - class A(object): - locals()[42] = 3 - - won't work. - -A more complete list is available at `our dev site`_. +A more complete list of known differences is available at `our dev site`_. .. _`CPython C API`: http://docs.python.org/c-api/ .. _`CFFI`: http://cffi.readthedocs.org/