<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="http://nedbatchelder.com/rssfull2html.xslt" media="screen" ?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns="http://purl.org/rss/1.0/">
	<channel rdf:about="http://nedbatchelder.com//blog">
		<title>Ned Batchelder's blog</title>
		<link>http://nedbatchelder.com/blog</link>
		<description>Ned Batchelder's personal blog.</description>
		<dc:language>en-US</dc:language>
		<image rdf:resource="http://nedbatchelder.com/pix/rss-banner.gif"/>
		<items>
			<rdf:Seq>
				<rdf:li resource="http://nedbatchelder.com/blog/201306/explaining_descriptors.html"/><rdf:li resource="http://nedbatchelder.com/blog/201306/51_at_momath.html"/><rdf:li resource="http://nedbatchelder.com/blog/201306/filter_a_list_into_two_parts.html"/><rdf:li resource="http://nedbatchelder.com/blog/201305/what_made_you_feel_competent_in_python.html"/><rdf:li resource="http://nedbatchelder.com/blog/201305/mary_elas_transitional_gravestone.html"/><rdf:li resource="http://nedbatchelder.com/blog/201304/config_files_dot_or_not.html"/><rdf:li resource="http://nedbatchelder.com/blog/201303/community_conduct_conflict_and_communication.html"/><rdf:li resource="http://nedbatchelder.com/blog/201303/pycon_acheivements.html"/><rdf:li resource="http://nedbatchelder.com/blog/201303/loop_like_a_native.html"/><rdf:li resource="http://nedbatchelder.com/blog/201303/letterpress_workshop_at_massart.html"/>
			</rdf:Seq>
		</items>
	</channel>
	<image rdf:about="http://nedbatchelder.com/pix/rss-banner.gif">
		<title>Ned Batchelder's blog</title>
		<link>http://nedbatchelder.com/blog</link>
		<url>http://nedbatchelder.com/pix/rss-banner.gif</url>
	</image>
	
	<item rdf:about="http://nedbatchelder.com/blog/201306/explaining_descriptors.html">
		<title>Explaining descriptors</title>
		<link>http://nedbatchelder.com/blog/201306/explaining_descriptors.html</link>
		
		<dc:date>2013-06-18T20:09:49-04:00</dc:date>
		<dc:creator>Ned Batchelder</dc:creator>
		<description><![CDATA[<p>I've always found descriptors to be one of the more confusing corners of Python.
        Partly, I think that's to do with the <a class="offsite" href="http://docs.python.org/2/howto/descriptor.html">explanations in the docs</a>,
        which I find opaque:
    </p><blockquote><div><p>In general, a descriptor is an object attribute with “binding
            behavior”, one whose attribute access has been overridden by
            methods in the descriptor protocol.</p></div></blockquote><p>What is binding behavior, and why is it in quotes?  This lead sentence hints at
        overriding attribute access, but doesn't tell me how it happens. It's a tall
        wall to scale right at the start of the learning process.</p><p>The best explanation I've seen of what descriptors do and why you'd want to write them
        was in Chris Beaumont's lightning talk at Boston Python, 
        <a href="https://www.youtube.com/watch?v=9A1ycvcgc_U">Demystifying Descriptors in 5 Minutes</a>.
        The video quality was not great, but now Chris has written it up: <a class="offsite" href="http://bit.ly/dscrptrs">Python Descriptors Demystified</a>.</p><p align="center"><iframe width="560" height="315" src="http://www.youtube.com/embed/9A1ycvcgc_U" frameborder="0" allowfullscreen="allowfullscreen"></iframe></p><p>(Sorry about the quality, we're getting much better... PS: subscribe to
        our <a class="offsite" href="http://youtube.com/bostonpython">YouTube channel</a>!)</p><p>Chris' insight was that instead of defining descriptors, and then
        showing how you could make properties with them, he flipped that
        explanation around: explain properties, then show how descriptors are
        like generalized properties. Read the whole thing: <a class="offsite" href="http://bit.ly/dscrptrs">Python Descriptors Demystified</a>.</p><p>When explaining things, you have to build from what people already know,
        a step at a time.  I picture a student's understanding being like
        geography.  What they know is a land mass, and when you teach them, you
        are extending their land out into the unknown ocean.  You want to make
        their island bigger, and there's a particular point out in the ocean
        you want to encompass.</p><p>Some technical descriptions will explain that distant point, and either
        hope you can build the peninsula yourself, or expect to be able to
        build backwards toward the mainland.  The classic descriptor
        explanation is like that: provide a definition of the distant concept,
        and hope students can make the leap.</p><p>Chris' explanation is more incremental.  Start with what we know, and extend
        a little bit at a time, with motivations as we go. I love it.</p><p>BTW: I made some edits to the Python documentation, but they haven't been 
        adopted: <a class="offsite" href="http://bugs.python.org/issue17894">Edits to descriptor howto</a>.
        Others have also suggested reorganizations of the docs about descriptors: 
        <a class="offsite" href="http://bugs.python.org/issue12077">Harmonizing descriptor protocol documentation</a>.</p><p>Descriptors are still an advanced feature, and I don't expect everyone to understand
        and use them.  But they are not as complicated as they first seem, and the
        explanations can do a better job helping people up that learning curve.</p>
]]></description>
	</item>
	
	<item rdf:about="http://nedbatchelder.com/blog/201306/51_at_momath.html">
		<title>51 at MoMath</title>
		<link>http://nedbatchelder.com/blog/201306/51_at_momath.html</link>
		
		<dc:date>2013-06-16T08:42:16-04:00</dc:date>
		<dc:creator>Ned Batchelder</dc:creator>
		<description><![CDATA[<p>For my birthday (today), we visited the <a class="offsite" href="http://momath.org/">Museum of Math</a>
        in New York (yesterday).  I've been looking forward to getting there
        since it opened six months ago, and my reluctant family had to accede
        to my birthday destination, so all five of us spent the afternoon.</p><p align="center"><a href="http://momath.org/"><img src="http://nedbatchelder.com/pix/momath.png" alt="Museum of Math" width="200" height="211"></a></p><p>The museum is a fun place, with lots of interactive exhibits.  Some were
        intriguing but baffling, like a polyhedron exploration device which
        looked great, but was impossible to control.  We rode square-wheeled
        tricycles, made ourselves into fractal trees, explored cross-sections
        in the wall of fire, rolled weird shapes to make weird paths, looked
        at <a class="offsite" href="http://www.zintaglio.com">specular holography</a>, and so
        on.</p><p>As is typical with these kinds of high-traffic interactive displays, a
        number of them were not working, which was disappointing.  But overall,
        it was a lot of fun, and not the same feel as math class at all.  One
        helpful museum worker kept popping up to tell us how to better use the
        exhibits, and Susan said, "if I had her as a math teacher, I might have
        learned something in high school!"</p><p>It was a great day.  If you enjoy mathematical thinking, I heartily
        recommend the Museum of Math.</p><p>A few blocks north, we found the Museum of Sex, but decided not to go in
        with the kids....</p>
]]></description>
	</item>
	
	<item rdf:about="http://nedbatchelder.com/blog/201306/filter_a_list_into_two_parts.html">
		<title>Filter a list into two parts</title>
		<link>http://nedbatchelder.com/blog/201306/filter_a_list_into_two_parts.html</link>
		
		<dc:date>2013-06-11T21:25:46-04:00</dc:date>
		<dc:creator>Ned Batchelder</dc:creator>
		<description><![CDATA[<p>A recent discussion on comp.lang.python asked how to
    <a href="https://groups.google.com/forum/?fromgroups=#!topic/comp.lang.python/7JzJaOC8CQM">Split a list into two parts based on a filter?</a>,
    and the answers were interesting and insightful.
</p><p>The question was by Roy Smith. He asked about dividing a list of songs into
    two lists based on a predicate, like this:</p><blockquote class="code"><tt><span class="n">new_songs</span>&#xA0;<span class="o">=</span>&#xA0;<span class="p">[</span><span class="n">s</span>&#xA0;<span class="k">for</span>&#xA0;<span class="n">s</span>&#xA0;<span class="ow">in</span>&#xA0;<span class="n">songs</span>&#xA0;<span class="k">if</span>&#xA0;<span class="n">s</span><span class="o">.</span><span class="n">is_new</span><span class="p">()]</span>
<br><span class="n">old_songs</span>&#xA0;<span class="o">=</span>&#xA0;<span class="p">[</span><span class="n">s</span>&#xA0;<span class="k">for</span>&#xA0;<span class="n">s</span>&#xA0;<span class="ow">in</span>&#xA0;<span class="n">songs</span>&#xA0;<span class="k">if</span>&#xA0;<span class="ow">not</span>&#xA0;<span class="n">s</span><span class="o">.</span><span class="n">is_new</span><span class="p">()]</span>
<br></tt></blockquote><p>but without iterating the list twice and calling the predicate twice for
    each element.  He also provided this implementation, which iterates the
    list only once:</p><blockquote class="code"><tt><span class="n">new_songs</span>&#xA0;<span class="o">=</span>&#xA0;<span class="p">[]</span>
<br><span class="n">old_songs</span>&#xA0;<span class="o">=</span>&#xA0;<span class="p">[]</span>
<br><span class="k">for</span>&#xA0;<span class="n">s</span>&#xA0;<span class="ow">in</span>&#xA0;<span class="n">songs</span><span class="p">:</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">if</span>&#xA0;<span class="n">s</span><span class="o">.</span><span class="n">is_new</span><span class="p">():</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="n">new_songs</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">else</span><span class="p">:</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="n">old_songs</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
<br></tt></blockquote><p>which got shortened to:</p><blockquote class="code"><tt><span class="n">new_songs</span><span class="p">,</span>&#xA0;<span class="n">old_songs</span>&#xA0;<span class="o">=</span>&#xA0;<span class="p">[],</span>&#xA0;<span class="p">[]</span>
<br><span class="k">for</span>&#xA0;<span class="n">s</span>&#xA0;<span class="ow">in</span>&#xA0;<span class="n">songs</span><span class="p">:</span>&#xA0;
<br>&#xA0;&#xA0;&#xA0;&#xA0;<span class="p">(</span><span class="n">new_songs</span>&#xA0;<span class="k">if</span>&#xA0;<span class="n">s</span><span class="o">.</span><span class="n">is_new</span><span class="p">()</span>&#xA0;<span class="k">else</span>&#xA0;<span class="n">old_songs</span><span class="p">)</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
<br></tt></blockquote><p>This works just fine for a simple list, but suppose the original sequence
    to be divided was a generator, and you don't want to buffer all the values
    in memory?  Is there a way to do this lazily?</p><p>Usually, we go to the <a class="offsite" href="http://docs.python.org/2/library/itertools.html">itertools module</a>
    for things like this, but this problem is tricky:  we need to get two lazy
    iterators at once.</p><p>Chris Angelico came up with this remarkable machine, with a deque tweak
    by Tim Chase:</p><blockquote class="code"><tt><span class="k">def</span>&#xA0;<span class="nf">iterpartition</span><span class="p">(</span><span class="n">pred</span><span class="p">,</span>&#xA0;<span class="n">it</span><span class="p">):</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;<span class="sd">&quot;&quot;&quot;Partition&#xA0;an&#xA0;iterable&#xA0;based&#xA0;on&#xA0;a&#xA0;predicate.</span>
<br>
<br><span class="sd">&#xA0;&#xA0;&#xA0;&#xA0;Returns&#xA0;two&#xA0;iterables,&#xA0;for&#xA0;those&#xA0;with&#xA0;pred&#xA0;False&#xA0;and&#xA0;those&#xA0;True.</span>
<br><span class="sd">&#xA0;&#xA0;&#xA0;&#xA0;&quot;&quot;&quot;</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;<span class="n">falses</span><span class="p">,</span>&#xA0;<span class="n">trues</span>&#xA0;<span class="o">=</span>&#xA0;<span class="n">collections</span><span class="o">.</span><span class="n">deque</span><span class="p">(),</span>&#xA0;<span class="n">collections</span><span class="o">.</span><span class="n">deque</span><span class="p">()</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;<span class="n">it</span>&#xA0;<span class="o">=</span>&#xA0;<span class="nb">iter</span><span class="p">(</span><span class="n">it</span><span class="p">)</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">def</span>&#xA0;<span class="nf">get_false</span><span class="p">():</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">while</span>&#xA0;<span class="bp">True</span><span class="p">:</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">if</span>&#xA0;<span class="n">falses</span><span class="p">:</span>&#xA0;
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">yield</span>&#xA0;<span class="n">falses</span><span class="o">.</span><span class="n">popleft</span><span class="p">()</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">else</span><span class="p">:</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">while</span>&#xA0;<span class="bp">True</span><span class="p">:</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="n">val</span>&#xA0;<span class="o">=</span>&#xA0;<span class="nb">next</span><span class="p">(</span><span class="n">it</span><span class="p">)</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">if</span>&#xA0;<span class="n">pred</span><span class="p">(</span><span class="n">val</span><span class="p">):</span>&#xA0;
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="n">trues</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">val</span><span class="p">)</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">else</span><span class="p">:</span>&#xA0;
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">break</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">yield</span>&#xA0;<span class="n">val</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">def</span>&#xA0;<span class="nf">get_true</span><span class="p">():</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">while</span>&#xA0;<span class="bp">True</span><span class="p">:</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">if</span>&#xA0;<span class="n">trues</span><span class="p">:</span>&#xA0;
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">yield</span>&#xA0;<span class="n">trues</span><span class="o">.</span><span class="n">popleft</span><span class="p">()</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">else</span><span class="p">:</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">while</span>&#xA0;<span class="bp">True</span><span class="p">:</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="n">val</span>&#xA0;<span class="o">=</span>&#xA0;<span class="nb">next</span><span class="p">(</span><span class="n">it</span><span class="p">)</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">if</span>&#xA0;<span class="ow">not</span>&#xA0;<span class="n">pred</span><span class="p">(</span><span class="n">val</span><span class="p">):</span>&#xA0;
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="n">falses</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">val</span><span class="p">)</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">else</span><span class="p">:</span>&#xA0;
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">break</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">yield</span>&#xA0;<span class="n">val</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">return</span>&#xA0;<span class="n">get_false</span><span class="p">(),</span>&#xA0;<span class="n">get_true</span><span class="p">()</span>
<br></tt></blockquote><p>Here two generators are created as closures, and returned as the result of
    the function.  The generators cooperate to work over the original iterable,
    calling the predicate only once for each element, and buffering only enough
    values to find the next one you want.</p><p>Peter Otten contributed this gem:</p><blockquote class="code"><tt><span class="k">def</span>&#xA0;<span class="nf">partition</span><span class="p">(</span><span class="n">items</span><span class="p">,</span>&#xA0;<span class="n">predicate</span><span class="o">=</span><span class="nb">bool</span><span class="p">):</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;<span class="n">a</span><span class="p">,</span>&#xA0;<span class="n">b</span>&#xA0;<span class="o">=</span>&#xA0;<span class="n">itertools</span><span class="o">.</span><span class="n">tee</span><span class="p">((</span><span class="n">predicate</span><span class="p">(</span><span class="n">item</span><span class="p">),</span>&#xA0;<span class="n">item</span><span class="p">)</span>&#xA0;<span class="k">for</span>&#xA0;<span class="n">item</span>&#xA0;<span class="ow">in</span>&#xA0;<span class="n">items</span><span class="p">)</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">return</span>&#xA0;<span class="p">((</span><span class="n">item</span>&#xA0;<span class="k">for</span>&#xA0;<span class="n">pred</span><span class="p">,</span>&#xA0;<span class="n">item</span>&#xA0;<span class="ow">in</span>&#xA0;<span class="n">a</span>&#xA0;<span class="k">if</span>&#xA0;<span class="ow">not</span>&#xA0;<span class="n">pred</span><span class="p">),</span>
<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="p">(</span><span class="n">item</span>&#xA0;<span class="k">for</span>&#xA0;<span class="n">pred</span><span class="p">,</span>&#xA0;<span class="n">item</span>&#xA0;<span class="ow">in</span>&#xA0;<span class="n">b</span>&#xA0;<span class="k">if</span>&#xA0;<span class="n">pred</span><span class="p">))</span>
<br></tt></blockquote><p>Here we finally have itertools helping us.  This behaves like Chris' code,
    buffering enough values for either returned iterable to provide the next
    requested value.  But we don't have to do the buffering, itertools.tee
    does it for us, and the predicate is called only once for each element
    in the iterable.  Itertools.tee gets a generator expression that produces
    the original elements along with the result of calling the predicate. That
    is tee'd into two iterables, which are then fed to two generator expressions
    to select the proper values.  Clever.</p><p>When I first read the question on the list, I didn't see how to improve
    on the list-building code.  Now I've got two interesting implementations,
    and I learned a few things!</p>
]]></description>
	</item>
	
	<item rdf:about="http://nedbatchelder.com/blog/201305/what_made_you_feel_competent_in_python.html">
		<title>What made you feel competent in Python?</title>
		<link>http://nedbatchelder.com/blog/201305/what_made_you_feel_competent_in_python.html</link>
		
		<dc:date>2013-05-23T22:12:06-04:00</dc:date>
		<dc:creator>Ned Batchelder</dc:creator>
		<description><![CDATA[<p>I'm trying to come up with more project ideas for intermediate learners,
        somewhat along the lines of <a href="https://openhatch.org/wiki/Intermediate_Python_Workshop/Projects">Intermediate Python Workshop Projects</a>.</p><p>So here's a question for people who remember coming up from beginner: as
        you moved from exercises like those in Learn Python the Hard Way, up to
        your own self-guided work on small projects, what project were you
        working on that made you feel independent and skilled?  What program
        first felt like your own work rather than an exercise the teacher had
        assigned?</p><p>I don't want anything too large, but big enough that there's room for
        design, and multiple approaches, etc.</p><p>If you came to Python from another programming language, then what was
        the project that first made you feel competent at programming in
        general?</p><p>Any and all ideas welcome. Thanks in advance!</p>
]]></description>
	</item>
	
	<item rdf:about="http://nedbatchelder.com/blog/201305/mary_elas_transitional_gravestone.html">
		<title>Mary Ela&#39;s transitional gravestone</title>
		<link>http://nedbatchelder.com/blog/201305/mary_elas_transitional_gravestone.html</link>
		
		<dc:date>2013-05-18T19:42:41-04:00</dc:date>
		<dc:creator>Ned Batchelder</dc:creator>
		<description><![CDATA[<p>I was walking through <a href="https://en.wikipedia.org/wiki/Copp%27s_Hill_Burying_Ground">Copp's Hill burying ground</a>
        in Boston's North End today.  The gravestones are fascinating, partly for the concrete connection
        to a distant past, but also for their antiquated style.
    </p><p>For example, many of the stones had y<sup>e</sup> in place of "the."  
        That y isn't actually a y, it's a <a class="offsite" href="http://en.wikipedia.org/wiki/Thorn_%28letter%29">thorn</a>,
        a letter that fell out of use in English a few hundred years ago.
        Thorn is prounounced th, so y<sup>e</sup> isn't "yee", it actually is "the."
    </p><p>After noticing how older stones had y<sup>e</sup> and newer ones had "the",
        we came across Mary Ela's stone:</p><p align="center"><a href="http://nedbatchelder.com/pix/mary_ela.jpg"><img src="http://nedbatchelder.com/pix/mary_ela_thumb.jpg" alt="Gravestone of Mary Ela, died 1737" width="500" height="281"></a></p><p>It reads:</p><blockquote><div>
        <p>HERE LYES BURIED<br>
            THE BODY OF M<sup>rs</sup>.<br>
            MARY ELA WHO<br>
            DEC<sup>D</sup>. MARCH Y<sup>e</sup> 6.<br>
            1 7 3 7<sub>/8</sub><br>
            IN Y<sup>e</sup> 55. YEAR<br>
            OF HER AGE.</p></div></blockquote><p>The odd thing here is a single gravestone that has both THE and Y<sup>e</sup>.
        Why use both forms?  Why in one place but not the other?  Perhaps because the
        English sentence flowed more naturally, but the dates and age felt like a 
        conventional form?</p><p>The other transitional note is the date:  1737/8.  The 7-or-8 was not because
        her date of death was unknown.  It's because the world didn't agree on how to
        number years.</p><p>Our current calendar is the <a class="offsite" href="http://en.wikipedia.org/wiki/Gregorian_calendar">Gregorian calendar</a>,
        a work of some engineering and design.  Before 1752, years started on the vernal equinox, around
        March 21st. It wasn't until 1752 that people agreed that the number of the year should be incremented
        on January 1st.  In 1737, some people used year numbers incremented on January 1st, and some used
        years incremented in March.  Since Mary Ela died in early March, some would have called the year
        1737, but some would have called it 1738.  Putting both numbers on the gravestone makes it clear
        when she died.</p><p>By the way: the year starting in March explains why September, October, November, and December
        are named as the 7th, 8th, 9th, and 10th months:  if you count March as the first month, then
        the numbering makes perfect sense.</p><p>It's fascinating to think back to those times.  We deal now with confusing timezones and character
        sets, but at least the English alphabet and the number of the year are simple, right? Well,
        back in 1737, you couldn't even count on that.</p>
]]></description>
	</item>
	
	<item rdf:about="http://nedbatchelder.com/blog/201304/config_files_dot_or_not.html">
		<title>Config files: dot or not?</title>
		<link>http://nedbatchelder.com/blog/201304/config_files_dot_or_not.html</link>
		
		<dc:date>2013-04-25T19:31:02-04:00</dc:date>
		<dc:creator>Ned Batchelder</dc:creator>
		<description><![CDATA[<p><a href="http://nedbatchelder.com/code/coverage">Coverage.py</a> reads a configuration file,
        which by default is in .coveragerc, with a leading dot.  For years I thought 
        <a class="offsite" href="http://www.pylint.org/">Pylint</a> had no default config
        file, because it wouldn't find .pylintrc, it turns out it looks by
        default for pylintrc, no leading dot.</p><p>Which is correct?</p><p>I guess I was modeling .coveragerc on .bashrc, .vimrc, and all the other
        files that clutter home directories everywhere. But is that right?  I
        <a href="https://twitter.com/nedbat/status/300737626611273728">asked on twitter</a> 
        a few months ago:</p><blockquote><div><p>Should config files have initial dots or not? tox.ini vs .gitignore, for example. Reasons?</p></div></blockquote><p>A few people said they should have dots if they are in your home directory,
        which is clearly true.  But these config files are not meant for the home directory.</p><p><a href="https://twitter.com/laprice/status/300740793390477312">Larry Price responded</a>,</p><blockquote><div><p>essential versus incidental, .gitignore or .bashrc are incidental
            to any given task, but tox.ini or settings.py are the task
            itself.</p></div></blockquote><p>Hmm, an interesting point.  So is .coveragerc essential to coverage.py?  It's
        only for overriding defaults, so it isn't required.  But it does specify how
        coverage.py should behave.</p><p>Should it be coveragerc instead?  Or coverage.rc? Opinions?  Of course,
        .coveragerc files will still be recognized if a new default is used. I
        know this is a small point, but I'd like to follow the consensus if
        there is one.</p>
]]></description>
	</item>
	
	<item rdf:about="http://nedbatchelder.com/blog/201303/community_conduct_conflict_and_communication.html">
		<title>Community, conduct, conflict, and communication</title>
		<link>http://nedbatchelder.com/blog/201303/community_conduct_conflict_and_communication.html</link>
		
		<dc:date>2013-03-23T14:12:24-04:00</dc:date>
		<dc:creator>Ned Batchelder</dc:creator>
		<description><![CDATA[<p>The fallout from PyCon this year has been dramatic, involving Adria
        Richards, Alex Reid, SendGrid, PlayHaven, and the PyCon organizers.  I
        wasn't involved in this event at all, so I have no first-hand knowledge
        of it, but it saddens me greatly.  So many things have happened that I
        wish had not happened.</p><p>Improving community is difficult. Getting 2500 people together without
        friction is impossible. Friction and offense will happen, the question
        is, what do we do about it?  It seems to me there are two mindsets
        about how to improve a community.</p><p>The first mindset is, "Let's get rid of the assholes, and the people
        that are left will be a great community."  I'll call this the
        <strong>shunning model</strong>: identify the Bad People, get rid of
        them, and you will have only Good People left.</p><p>The second mindset is, "We're all different, and we're going to make
        mistakes, so let's be thoughtful and educate each other."  I'll call
        this the <strong>educating model</strong>: people are imperfect, but
        basically good, and if we can keep an eye on things and keep
        communicating, we can all improve.</p><p>When I look back at the aftermath of PyCon, I see a number of events
        that fit into the shunning model, and few that fit into the education
        model.  This to me seems to be the heart of the problem.</p><p>We often talk about building an inclusive community, which usually means
        that women should be as welcome as men.  I want it to also mean that
        people who make mistakes can be kept as members.  Clearly, some people
        will be difficult enough that they won't be welcome, but most people
        who offend are good people who've made a mistake, not incorrigible
        assholes. I don't want a One Strike And You're Out community.</p><p>Let me tell you about my experiences at PyCon.  I had at least three
        incidents of "community friction" during my time there:</p><ul>
        <li>Friday at lunch, I sat across the table from a friend of mine. I 
            made a joke that she found mean, and she told me so.  I felt terrible,
            and apologized to her then, and again later when I saw her next.</li>

        <li>Saturday night, I was at the rowdy event that engendered a formal
            response from PyCon: <a class="offsite" href="http://term.ie/blog/how-to-get-banned-from-pycon/">a
                member was ejected and banned</a> from PyCon.  I was more than
            just an observer: I tried to talk to the member about what he had
            said. I also helped report it to the PyCon organizers.</li>

        <li>Monday morning, I was having breakfast with a group of people, both
            friends and new acquaintances, when someone used the word
            "retarded" to refer to some suboptimal technical detail.  I don't
            like people using "retarded" as humor.  I said nothing, but winked
            across the table to a friend to say, "yup, I heard it, I wish he
            wouldn't say that, but I'm not saying anything about it."</li>

    </ul><p>In incident #1, I was the offender, and I'm really glad I was educated
        instead of shunned.</p><p>In incident #2, I was the offended.  The member in question has been
        banned.  I wasn't part of deciding the sanctions, but am glad to see in
        his blog post that he is thoughtful about what happened.</p><p>In incident #3, I was the offended, but did nothing.  If I had known the
        speaker better, I might have said, "I wish you wouldn't use that word
        that way," but it didn't seem right at the time.</p><p>Friction is inevitable.  One of the great things about PyCon is that it
        is right at the boundary between being comfortable with old friends,
        and meeting new people.  There are bound to be incidents.  We have to
        accept that, and try hard to talk to each other to improve things for
        everyone.</p><p>Education is better than shunning.</p>
]]></description>
	</item>
	
	<item rdf:about="http://nedbatchelder.com/blog/201303/pycon_acheivements.html">
		<title>PyCon acheivements</title>
		<link>http://nedbatchelder.com/blog/201303/pycon_acheivements.html</link>
		
		<dc:date>2013-03-18T12:18:09-04:00</dc:date>
		<dc:creator>Ned Batchelder</dc:creator>
		<description><![CDATA[<p>Here at PyCon, attendees get the usual ribbons dangling from their
        badges: Speaker, Sponsor, etc.  They're always a topic of conversation,
        especially if you have three or more, or are wearing any of the joke
        ones like "Workaholic" or "King".</p><p>But most attendees have no ribbons, and it occured to me we could have
        tokens for everyone.  I thought of them as merit badges, but the more
        current terminology would be acheivements.</p><p>For example:</p><ul>
        <li>I wrote a metaclass</li>
        <li>I avoided writing a metaclass!</li>
        <li>I introduced a friend to Guido</li>
        <li>I contributed to CPython</li>
        <li>I grok PyPy</li>
        <li>I taught a kid to program</li>
    </ul><p>And so on.  Could be fun.</p>
]]></description>
	</item>
	
	<item rdf:about="http://nedbatchelder.com/blog/201303/loop_like_a_native.html">
		<title>Loop Like a Native</title>
		<link>http://nedbatchelder.com/blog/201303/loop_like_a_native.html</link>
		
		<dc:date>2013-03-16T17:01:50-04:00</dc:date>
		<dc:creator>Ned Batchelder</dc:creator>
		<description><![CDATA[<p>I gave a talk yesterday at PyCon 2013 called
        <a href="http://nedbatchelder.com/text/iter.html">Loop Like a Native</a>.
        The main point was: write more generators.  Give it a look.
    </p>
]]></description>
	</item>
	
	<item rdf:about="http://nedbatchelder.com/blog/201303/letterpress_workshop_at_massart.html">
		<title>Letterpress workshop at MassArt</title>
		<link>http://nedbatchelder.com/blog/201303/letterpress_workshop_at_massart.html</link>
		
		<dc:date>2013-03-03T11:36:02-05:00</dc:date>
		<dc:creator>Ned Batchelder</dc:creator>
		<description><![CDATA[<p>I have long been interested in the technology of printing, especially
    typography.  Two years ago, when I went to the <a href="http://nedbatchelder.com/blog/201103/boston_printing_office_auction.html">Boston Printing Office auction</a>,
    I met Keith Cross, a lecturer at MassArt.  He teaches letterpress classes, usually 
    spread over the course of a semester, which I wasn't able to commit to.
    When he announced a <a class="offsite" href="http://www.milkrow.com/letterpressclasses.html">one-day Saturday workshop</a>,
    I jumped at it.  It happened yesterday, and I loved it.</p><p align="center"><a href="http://nedbatchelder.com/pix/lpworkshop/DSC_9314.jpg"><img src="http://nedbatchelder.com/pix/lpworkshop/DSC_9314_thumb.jpg" alt="Initial setup for the class" width="500" height="332"></a></p><p>The workshop is hands-on: you start off standing at a type case, and with a few
    minutes of verbal instruction, you start putting type into a job stick:</p><p align="center"><a href="http://nedbatchelder.com/pix/lpworkshop/DSC_9316.jpg"><img src="http://nedbatchelder.com/pix/lpworkshop/DSC_9316_thumb.jpg" alt="Me, setting type the old-fashioned way." width="500" height="332"></a></p><p>I was familiar with the concepts of cold metal type, job sticks, 
    <a class="offsite" href="http://en.wikipedia.org/wiki/California_Job_Case">California cases</a>,
    and so on, but had never had a chance to try it myself.
    I was really pleased to be able to work with these little pieces of
    metal, and set actual lines of type.</p><p>You don't need to know the history of type to take the class, Keith explains
    what you need to know, and walks around gently guiding people to get them over
    rough spots.</p><p>I was having fun, and so went a little overboard.  I wanted to use the fancy
    ligatures, so I included words like, "fluffy waffles," and when I saw that
    my type case had a "gg" ligature, I had to add "eggs." Then I
    discovered it had "zy" and "gy" ligatures, so I couldn't stop until I got
    "<a class="offsite" href="http://dictionary.reference.com/browse/syzygy">syzygy</a>" in
    there!</p><p align="center"><a href="http://nedbatchelder.com/pix/lpworkshop/DSC_9321.jpg"><img src="http://nedbatchelder.com/pix/lpworkshop/DSC_9321_thumb.jpg" alt="My job stick with three complete lines of type" width="500" height="332"></a></p><p>Each student produced a few lines of type, then we all headed over to the
    press to assemble them together into a page:</p><p align="center"><a href="http://nedbatchelder.com/pix/lpworkshop/DSC_9322.jpg"><img src="http://nedbatchelder.com/pix/lpworkshop/DSC_9322_thumb.jpg" alt="Putting lines of type onto the bed of the press" width="500" height="332"></a></p><p>Once we had all contributed our lines, Keith added larger blocks of iron
    and wood, known as "furniture" around it to hold it all in place, and 
    locked it in with quoins.</p><p align="center"><a href="http://nedbatchelder.com/pix/lpworkshop/DSC_9329.jpg"><img src="http://nedbatchelder.com/pix/lpworkshop/DSC_9329_thumb.jpg" alt="A full page of type, ready to print" width="465" height="700"></a></p><p>A little discussion of paper, the mechanics of the press, then Keith rolls the
    press, and there's a printed sheet!</p><p align="center"><a href="http://nedbatchelder.com/pix/lpworkshop/DSC_9331.jpg"><img src="http://nedbatchelder.com/pix/lpworkshop/DSC_9331_thumb.jpg" alt="The first sheet off the press" width="465" height="700"></a></p><p>The first sheet is called a proof, because it's used to check the typesetting.
    The next step is to read the proof, an activity known as "proofreading"!
    One of the things I find fascinating about type is how history bleeds through
    into the present in the terminology and conventions.  "Leading" makes much
    more visceral sense when you are holding a 6-pt thick bar of lead alloy, and
    place it between your rows of type.</p><p align="center"><a href="http://nedbatchelder.com/pix/lpworkshop/DSC_9332.jpg"><img src="http://nedbatchelder.com/pix/lpworkshop/DSC_9332_thumb.jpg" alt="Reading the proof" width="500" height="598"></a></p><p>Mistakes were identified, as were worn pieces of type.  The form in the press
    was unlocked, and corrections made, by pulling out bits of type with a tweezers,
    inserting new ones, adjusting spacing, and so on.  Then we each printed a
    sheet of our own.</p><p>When the printing was done, and the type had been cleaned, we each retrieved our lines
    of type, and put each tiny piece back into the proper compartment.  Thinking about
    how long it took to find the type, set the type, adjust the type, print the type, and
    then clean up and put away the type, I am amazed anew that books, newspapers,
    and even encyclopedias ever got printed.  This was very labor-intensive, dirty work.
    A few hours in a letterpress shop, and it is clearly industry.</p><p>After lunch, we each worked on a project of our own.  I chose a quote from
    E.B. White:</p><blockquote><div><p>Creation is in part merely the business of forgoing the great and small distractions.</p></div></blockquote><p>I liked it not only for what it says, but because the words "great" and "small" could
    be used for a little type expression.</p><p>Here's where the old ways really seemed difficult!  I wasn't sure what layout to
    use, and ended up changing my mind half-way through. So I had to move rows of
    metal chunks from one line to the next, and hope not to drop the whole thing.</p><p>Each line has to be completely packed tight with metal so that when the type is 
    on the press, it will all be held tightly in place.  This means that you need to
    find just the right thickness to fill the gaps, perhaps even slivers of brass to
    finish a tiny space.</p><p align="center"><a href="http://nedbatchelder.com/pix/lpworkshop/DSC_9335.jpg"><img src="http://nedbatchelder.com/pix/lpworkshop/DSC_9335_thumb.jpg" alt="My chosen quote, set in cold metal type" width="500" height="332"></a></p><p>I wanted an em-dash, but there wasn't one in my type case.  We made one with a
    36-pt piece of metal, spaced properly with yet more tiny chunks of metal.
    After dealing digitally with different kinds of spaces and dashes and leading,
    it was a new perspective to have to actually build it from pieces of metal.</p><p>To add to the complexity, the quote is set in 36-pt Centaur, but the word
    "small" is in 30-pt.  I had to make up the 6-pt difference with strips of
    metal just as long as the word "small", but some above and some below to
    get the baseline right.  I'd like to have used 24-pt for greater
    differentiation, but the next available size below 30 was 18.  Another
    analog limitation.</p><p>When it was my turn for the press, Keith set up the form and locked it in,
    and I printed off a few dozen on gold paper:</p><p align="center"><a href="http://nedbatchelder.com/pix/lpworkshop/DSC_9336.jpg"><img src="http://nedbatchelder.com/pix/lpworkshop/DSC_9336_thumb.jpg" alt="My type, in the press" width="500" height="332"></a></p><p>Even before I printed it, there were things I wished I could improve about the
    layout, but time (and ability!) were short.  The stars are there kind of as
    a distraction, but also because it's fun to use ornaments.  But they are too
    low for the line: you can see in the photo, they are cast on a 36-pt body like
    the rest of the type, but they have a much lower baseline. I'm not even sure how
    I would have adjusted for that even if I had had time.</p><p>But I'm still very pleased with the result:</p><p align="center"><a href="http://nedbatchelder.com/pix/lpworkshop/DSC_9338.jpg"><img src="http://nedbatchelder.com/pix/lpworkshop/DSC_9338_thumb.jpg" alt="The finished result" width="500" height="332"></a></p><p>Keith made the day fun, he's friendly, passionate, knowledgable, and
    helpful.  I highly recommend his
    <a class="offsite" href="http://www.milkrow.com/letterpressclasses.html">class</a>, it's a
    great way to see what letterpress is all about.  It gives you a whole new
    perspective on type, and the technology that brought us to our current tools
    and techniques.</p>
]]></description>
	</item>
	
</rdf:RDF>
