<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-9320223</id><updated>2009-02-22T01:03:44.061+10:00</updated><title type='text'>Boredom &amp; Laziness</title><subtitle type='html'>There are a couple of very, very scary things in this world. The first is a bored human. Bored humans have time to indulge their curiosity, with potentially amazing results. The second is a lazy human. Lazy humans can be quite inventive when it comes to figuring out how to do less work. So, here's to boredom &amp; laziness - two of the prime movers in human progress!</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://boredomandlaziness.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default'/><link rel='alternate' type='text/html' href='http://boredomandlaziness.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Nick</name><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>14</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-9320223.post-3303716936699342280</id><published>2007-06-24T10:19:00.000+10:00</published><updated>2007-06-24T10:21:38.858+10:00</updated><title type='text'>What he said</title><content type='html'>Occasionally you can come across an article which summarises your own thoughts so well, you don't really need to add anything. For me, the author's note on the linked webcomic is such an article.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9320223-3303716936699342280?l=boredomandlaziness.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='related' href='http://www.irregularwebcomic.net/1609.html' title='What he said'/><link rel='replies' type='application/atom+xml' href='http://boredomandlaziness.blogspot.com/feeds/3303716936699342280/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9320223&amp;postID=3303716936699342280' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/3303716936699342280'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/3303716936699342280'/><link rel='alternate' type='text/html' href='http://boredomandlaziness.blogspot.com/2007/06/what-he-said.html' title='What he said'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06437087323095993816'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9320223.post-114442495473651573</id><published>2006-04-08T01:49:00.000+10:00</published><updated>2006-04-08T01:55:11.993+10:00</updated><title type='text'>Ego Surfing</title><content type='html'>So, one of Techdirt's latest stories led me back to &lt;a href="http://www.canton.elegal.ca/archives/2006/02/internet_privac.html"&gt;this article&lt;/a&gt; about the perils of putting too much personal info on line. Possibly even things like having the words "boredom" and "laziness" as part of a domain name you own, and then not updating the associated website for months on end, so people googling your name can wonder about your follow-through when it comes to keeping up with projects you start*.&lt;br /&gt;&lt;br /&gt;Anyway, as a result I did a bit of googling of my own. It used to be that Google gave me &lt;a href="http://www.boredomandlaziness.org/2004/12/google-footprint.html"&gt; far more prominence&lt;/a&gt; than one might expect, with buckets of references to python-list and python-dev posts. When I noticed those posts weren't on the first list of results anymore, and links for both the actor and the surfer were now included, I thought Google might have done something to give the non-mailing list results more importance, and give a result that better reflected mainstream celebrity.&lt;br /&gt;&lt;br /&gt;A closer look though and I find that while the list of sites has changed, my original opinion still holds: even with a lot more mainstream media moving online, your Google footprint still says far more about your online presence than your fame (or lack thereof) in the offline world. And I still manage to find that fact both obvious and intriguing at the same time :)&lt;br /&gt;&lt;br /&gt;*(FWIW, most of the stuff I write online is Python related, and ends up on the Python mailing lists rather than here)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9320223-114442495473651573?l=boredomandlaziness.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://boredomandlaziness.blogspot.com/feeds/114442495473651573/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9320223&amp;postID=114442495473651573' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/114442495473651573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/114442495473651573'/><link rel='alternate' type='text/html' href='http://boredomandlaziness.blogspot.com/2006/04/ego-surfing.html' title='Ego Surfing'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06437087323095993816'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9320223.post-112186466365782766</id><published>2005-07-20T23:04:00.000+10:00</published><updated>2005-07-20T23:04:23.660+10:00</updated><title type='text'>Lance &amp; Hannah</title><content type='html'>&lt;a href="http://www.flickr.com/photos/ncoghlan/27325255/" title="photo sharing"&gt;&lt;img src="http://photos21.flickr.com/27325255_322a99bc8e_m.jpg" alt="" style="border: solid 2px #000000;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size: 0.9em; margin-top: 0px;"&gt;&lt;a href="http://www.flickr.com/photos/ncoghlan/27325255/"&gt;Lance &amp;amp; Hannah&lt;/a&gt; &lt;br /&gt;Originally uploaded by &lt;a href="http://www.flickr.com/people/ncoghlan/"&gt;Nick Coghlan&lt;/a&gt;.&lt;/span&gt;&lt;br clear="all" /&gt;&lt;p&gt;Lance &amp; Hannah in Japan&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9320223-112186466365782766?l=boredomandlaziness.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://boredomandlaziness.blogspot.com/feeds/112186466365782766/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9320223&amp;postID=112186466365782766' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/112186466365782766'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/112186466365782766'/><link rel='alternate' type='text/html' href='http://boredomandlaziness.blogspot.com/2005/07/lance-hannah.html' title='Lance &amp; Hannah'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06437087323095993816'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9320223.post-112186192602768737</id><published>2005-07-20T22:18:00.000+10:00</published><updated>2005-07-20T22:20:38.473+10:00</updated><title type='text'>Grand Column</title><content type='html'>&lt;p&gt;This marble column from the Oregon Caves looks pretty impressive.&lt;/p&gt;&lt;a href="http://www.flickr.com/photos/ncoghlan/7085212/" title="photo sharing"&gt;&lt;img src="http://photos5.flickr.com/7085212_910b44b72d_m.jpg" alt="" style="border: solid 2px #000000;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size: 0.9em; margin-top: 0px;"&gt;&lt;a href="http://www.flickr.com/photos/ncoghlan/7085212/"&gt;Grand Column&lt;/a&gt; &lt;br /&gt;Originally uploaded by &lt;a href="http://www.flickr.com/people/ncoghlan/"&gt;Nick Coghlan&lt;/a&gt;.&lt;/span&gt;&lt;br clear="all" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;That is, until you see it with a person in the picture for scale ;)&lt;/p&gt;&lt;a href="http://www.flickr.com/photos/ncoghlan/7085241/" title="photo sharing"&gt;&lt;img src="http://photos6.flickr.com/7085241_4f3207e4bb_m.jpg" alt="" style="border: solid 2px #000000;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size: 0.9em; margin-top: 0px;"&gt;&lt;a href="http://www.flickr.com/photos/ncoghlan/7085241/"&gt;Or Maybe Not So Grand Column?&lt;/a&gt; &lt;br /&gt;Originally uploaded by &lt;a href="http://www.flickr.com/people/ncoghlan/"&gt;Nick Coghlan&lt;/a&gt;.&lt;/span&gt;&lt;br clear="all" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9320223-112186192602768737?l=boredomandlaziness.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://boredomandlaziness.blogspot.com/feeds/112186192602768737/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9320223&amp;postID=112186192602768737' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/112186192602768737'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/112186192602768737'/><link rel='alternate' type='text/html' href='http://boredomandlaziness.blogspot.com/2005/07/grand-column.html' title='Grand Column'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06437087323095993816'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9320223.post-111419014821727991</id><published>2005-04-23T03:15:00.000+10:00</published><updated>2005-04-23T03:15:48.216+10:00</updated><title type='text'>Self-defeating Advertisements</title><content type='html'>My main web browser is Mozilla Firefox. It has this lovely little extension called AdBlock, which let's me eliminate irritating content from the web pages I view. So what does that have to do with the title of the article?&lt;br /&gt;&lt;br /&gt;Simple: A lot of the time, I &lt;i&gt;do not switch AdBlock on&lt;/i&gt;. Normal banner ads, that generally stay out of my way, just plain don't bother me that much. I'm happy to let them appear on the screen (even if I don't click on them). As soon as an ad starts intruding on my web experience, though, out comes AdBlock, so I can say "Leave me the hell alone, you rude, pushy mongrels". Some ads get my attention without triggering that reflex (Absolut and IBM come to mind), because they don't block the main text, and are genuinely entertaining. Other ads (especially ones that interfere with real content) discover that getting too much of my attention can be a bad thing - it raises the irritation level enough to get me to take action. And, thanks to AdBlock's address wildcards, that will mean far more than just the one ad that triggered the block will be eliminated from my web surfing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9320223-111419014821727991?l=boredomandlaziness.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://boredomandlaziness.blogspot.com/feeds/111419014821727991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9320223&amp;postID=111419014821727991' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/111419014821727991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/111419014821727991'/><link rel='alternate' type='text/html' href='http://boredomandlaziness.blogspot.com/2005/04/self-defeating-advertisements.html' title='Self-defeating Advertisements'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06437087323095993816'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9320223.post-110761198544540995</id><published>2005-02-05T23:59:00.000+10:00</published><updated>2005-02-05T23:59:45.446+10:00</updated><title type='text'>Because James doesn't remember it</title><content type='html'>&lt;a href="http://www.thingsmygirlfriendandihavearguedabout.com/" target="_top"&gt;TMGAIHAA&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9320223-110761198544540995?l=boredomandlaziness.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://boredomandlaziness.blogspot.com/feeds/110761198544540995/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9320223&amp;postID=110761198544540995' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/110761198544540995'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/110761198544540995'/><link rel='alternate' type='text/html' href='http://boredomandlaziness.blogspot.com/2005/02/because-james-doesnt-remember-it.html' title='Because James doesn&apos;t remember it'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06437087323095993816'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9320223.post-110439602874040740</id><published>2004-12-30T18:40:00.000+10:00</published><updated>2004-12-30T22:57:49.120+10:00</updated><title type='text'>Anonymous functions in Python</title><content type='html'>Python currently supports anonymous functions using the &lt;code&gt;lambda&lt;/code&gt; keyword. This is a rather ugly beast, and I've yet to find anyone who actually &lt;i&gt;likes&lt;/i&gt; the syntax, rather than tolerating it because they want to be able to use anonymous functions. It also forces non-mathematicians to learn that mathemetaticians and functional programmers seem to like calling anonymous functions lambdas, for reasons known only to them.&lt;br /&gt;&lt;br /&gt;GvR has stated that he wants to get rid of &lt;code&gt;lambda&lt;/code&gt; for Python 3.0. His main reasons seem to be that he dislikes the restriction to a single expression, and that he dislikes the current syntax. The question then, is whether a more Pythonic syntax for anonymous functions can be found to replace the current &lt;code&gt;lambda&lt;/code&gt;, and whether the restriction to a single expression is really a problem.&lt;br /&gt;&lt;br /&gt;I believe Python 2.4's generator expressions provide good guidance on the correct attitude towards 'anonymous functions as expressions'. Generator expressions are related to &lt;code&gt;for&lt;/code&gt; loops similarly to the way anonymous functions are related to full function definitions. Firstly, generator expressions are restricted to a single expression in the "body" of the &lt;code&gt;for&lt;/code&gt; loop. They also include an implied &lt;code&gt;yield&lt;/code&gt; statement. That is, the following two pieces of code are equivalent (neglecting namespace effects):&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;sum(x * x for x in seq)&lt;br /&gt;&lt;br /&gt;def squares(seq):&lt;br /&gt;&amp;nbsp;&amp;nbsp;for x in seq:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;yield x * x&lt;br /&gt;sum(squares(seq))&lt;/code&gt;&lt;/blockquote&gt;Nobody seems to complain about the fact that generator expressions are restricted to a single expression inside the &lt;code&gt;for&lt;/code&gt; loop. Instead, they are extremely happy about the fact that they can do their simple &lt;code&gt;for&lt;/code&gt; loop inside an expression instead of breaking it out into a separate generator. I believe the same attitude should apply to anonymous functions - if something is simple enough to express with a single expression, it &lt;i&gt;may&lt;/i&gt; be simple enough to embed inside another expression (such as a function call). If it cannot be expressed with a single expression, it is almost certainly too complicated to be embedded inside another expression.&lt;br /&gt;&lt;br /&gt;The other argument in favour of the conceptual integrity of restricting anonymous functions to a single expression is Python's distinction between suites (which contain statements), statements (which contain expressions, statements or suites) and expressions (which contain only other expressions). Allowing a suite inside an anonymous function would break the concept of "expressions can only contain other expressions". Even if it turned out to be possible, it would do horrible things to Python's grammar, and open the door to some seriously unreadable code. Even when restricted to a single expression, overuse of lambdas can already lead to incomprehensible code (abuse of generator expressions can &lt;i&gt;also&lt;/i&gt; lead to unreadable code, so don't take that last comment as an argument against allowing anonymous functions).&lt;br /&gt;&lt;br /&gt;Even if you agree with me that restricting anonymous functions to a single expression is legitimate, that still leaves the question of "Why not just define a named function?". This is certainly GvR's standard response when questioned about the removal of &lt;code&gt;lambda&lt;/code&gt; in Python 3.0. To my mind, the killer app for a clean anonymous function syntax is lazy evaluation of function arguments - only performing a calculation if the function actually &lt;i&gt;needs&lt;/i&gt; that value. Another, rarer, use is the ability to have a generator expression which yields a sequence of functions. My examples will be based on these two use cases.&lt;br /&gt;&lt;br /&gt;The standard mechanism for lazy evaluation in Python is to write a function that accepts a zero-argument callable instead of the argument we want lazily evaluated. If the function actually needs the relevant argument, it invokes the callable and uses the returned value. This approach is very clean when the caller has a function on hand that produces the desired result. When they do not, the caller must create a zero-argument function to be passed as the lazy argument. This is generally either a &lt;code&gt;lambda&lt;/code&gt; or a named function created specifically for the purpose. Removing &lt;code&gt;lambda&lt;/code&gt; eliminates the choice - you must use a named function. That approach, however, gets rather silly if the caller has the actual desired argument value on hand:&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;accepts_lazy_arg(lambda: val)&lt;br /&gt;&lt;br /&gt;def ret_val():&lt;br /&gt;&amp;nbsp;&amp;nbsp;return val&lt;br /&gt;accepts_lazy_arg(ret_val)&lt;/code&gt;&lt;/blockquote&gt;The canonical use cases for lazy evaluation, of course, are short circuiting versions of functions which implement conditional expressions and switch statements.&lt;br /&gt;&lt;br /&gt;Moving on to the second use case, consider the toy problem of creating a list of incrementors - functions that add differing amounts to their arguments. With anonymous functions, this can be done with an expression, without them, it requires several statements:&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;funcs = [(lambda x: x + i) for i in range(10)]&lt;br /&gt;&lt;br /&gt;def incrementors():&lt;br /&gt;&amp;nbsp;&amp;nbsp;for i in range(10):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def incrementor(x):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return x + i&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;yield incrementor&lt;br /&gt;funcs = list(incrementors)&lt;/code&gt;&lt;/blockquote&gt;There &lt;i&gt;are&lt;/i&gt; legitimate use cases for anonymous functions. I don't use them very often, but when I do use them, it would be a genuine pain to work around not having them. So I would be very disappointed to see them disappear completely in Python 3.0. However, where I agree with GvR entirely is that the current syntax is as ugly as sin - I sometimes &lt;i&gt;don't&lt;/i&gt; use &lt;code&gt;lambda&lt;/code&gt; when it might be useful, simply because it is so ugly and un-Pythonic. That means it must be time to move on to a syntax proposal.&lt;br /&gt;&lt;br /&gt;The proposed syntax is based on the idea of functions as mappings from tuples of arguments to tuples of results. In mathematical terms, a function maps from a given domain (e.g. the Cartesian product of the real numbers) to a given range (e.g. negative pi inclusive to positive pi exclusive). Anonymous functions cover only those cases where the result tuple can be obtained from the input tuple using Python expressions. If you need something more complex, switch to using a named function (just as generator expressions require you to switch to a named generator if either the desired result or the filtration condition cannot be written as Python expressions)&lt;br /&gt;&lt;br /&gt;One of the problems with &lt;code&gt;lambda&lt;/code&gt; is that we already have a perfectly good function keyword in &lt;code&gt;def&lt;/code&gt;. So the proposed syntax uses &lt;code&gt;def&lt;/code&gt; in an expression context (where it is currently illegal). Another problem I personally have with &lt;code&gt;lambda&lt;/code&gt; is that it embeds a colon in the middle of an expression, which I find makes it difficult to parse the rest of the expression. So the proposed syntax uses the new keyword &lt;code&gt;to&lt;/code&gt; instead. The existing pseudo-keyword &lt;code&gt;as&lt;/code&gt; was considered, but it is already overloaded with enough uses, and the word &lt;code&gt;to&lt;/code&gt; better fits the above interpretation of the meaning of anonymous functions. One of GvR's criticisms of &lt;code&gt;lambda&lt;/code&gt; that I agree with is that it doesn't require parentheses arounds its argument list. So the proposed syntax requires parentheses around the argument list. Parentheses surrounding the entire anonymous function will be required, even as an argument to a single argument function call. This avoids ambiguity problems with returning a tuple from the anonymous function. All of which gives something like the following equivalent pieces of code:&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;accepts_func((def (a, b, c) to f(a) + g(b) - h(c)))&lt;br /&gt;&lt;br /&gt;def f1(a, b, c):&lt;br /&gt;&amp;nbsp;&amp;nbsp;return f(a) + g(b) - h(c)&lt;br /&gt;accepts_func(f1)&lt;/code&gt;&lt;/blockquote&gt;The proposed syntax can be read as "define an anonymous function from arguments a, b and c to the result f of a plus g of b minus h of c". Or, in a shorter form, "def from a, b and c to f a plus g b minus h c". An earlier version of this post actually contained a bug in the named function version - I had incorrectly used the name '&lt;code&gt;f&lt;/code&gt;', accidentally creating a recursive function. Anyway, using the proposed syntax, the examples above become:&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;accepts_lazy_arg(def () to val)&lt;br /&gt;&lt;br /&gt;funcs = [(def (x) to x + i) for i in range(10)]&lt;/code&gt;&lt;/blockquote&gt;An idea worth toying with is whether the argument list and the &lt;code&gt;to&lt;/code&gt; keyword should be optional when the argument list is empty. This makes calls to functions which take lazy arguments extremely clean - just take whatever the argument would have been using immediate evaluation, prepend "&lt;code&gt;(def &lt;/code&gt;" and append "&lt;code&gt;)&lt;/code&gt;". However, that approach may not be possible given the constraints of CPython's simple parser.&lt;br /&gt;&lt;br /&gt;Finally, no discussion that covers lazy evaluation would be complete without showing how conditional expressions with short-circuiting behaviour would look. The example usages assume a syntax which allows "&lt;code&gt;() to&lt;/code&gt;" to be omitted.&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;def either(condition, true_case, false_case):&lt;br /&gt;&amp;nbsp;&amp;nbsp;if condition:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return true_case()&lt;br /&gt;&amp;nbsp;&amp;nbsp;else:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return false_case()&lt;br /&gt;&lt;br /&gt;print either(A == B, (def "A equals B"), (def "A does not equal B"))&lt;br /&gt;either(thefile, (def thefile.close()), (def 0))&lt;/code&gt;&lt;/blockquote&gt;Note that this proposal does &lt;i&gt;not&lt;/i&gt; add any new capability to the Python language. Instead, it merely aims to provide a more Pythonic syntax for the existing &lt;code&gt;lambda&lt;/code&gt; expressions, with the aim of &lt;i&gt;retaining&lt;/i&gt; anonymous functions for the hypothetical Python 3.0.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9320223-110439602874040740?l=boredomandlaziness.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://boredomandlaziness.blogspot.com/feeds/110439602874040740/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9320223&amp;postID=110439602874040740' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/110439602874040740'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/110439602874040740'/><link rel='alternate' type='text/html' href='http://boredomandlaziness.blogspot.com/2004/12/anonymous-functions-in-python.html' title='Anonymous functions in Python'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06437087323095993816'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9320223.post-110388209637610627</id><published>2004-12-24T19:54:00.000+10:00</published><updated>2004-12-24T19:54:56.376+10:00</updated><title type='text'>Email Blogging</title><content type='html'>Just checking it works. Nothing to see here. Move along.&lt;br /&gt;&lt;br /&gt;-- &lt;br /&gt;Nick Coghlan   |   ncoghlan@email.com   |   Brisbane, Australia&lt;br /&gt;---------------------------------------------------------------&lt;br /&gt;             http://boredomandlaziness.skystorm.net&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9320223-110388209637610627?l=boredomandlaziness.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://boredomandlaziness.blogspot.com/feeds/110388209637610627/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9320223&amp;postID=110388209637610627' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/110388209637610627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/110388209637610627'/><link rel='alternate' type='text/html' href='http://boredomandlaziness.blogspot.com/2004/12/email-blogging.html' title='Email Blogging'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06437087323095993816'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9320223.post-110387989393663651</id><published>2004-12-24T19:18:00.000+10:00</published><updated>2004-12-25T01:06:29.336+10:00</updated><title type='text'>Type-checking in Python</title><content type='html'>So, Guido has brought up the idea of &lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=85551" title="Optional Static Typing" target="_top"&gt;optional static typing&lt;/a&gt; again, posting his current throughts on the idea, as well as noting what he sees as the problem areas.&lt;br /&gt;&lt;br /&gt;His favoured syntax is:&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace"&gt;&lt;br /&gt;def (a: sometype, b: sometype) -&gt; sometype:&lt;br /&gt;&amp;nbsp;&amp;nbsp;pass&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;Bleh. The main reason I dislike the current version of anonymous functions is because they embed a colon in the middle of an expression so you can probably guess how I feel about Guido's reuse of the colon here. And I've always quite liked VB's approach of using 'as' to indicate the return type of a function. Anyway, syntax aside, there's a question of what the optional type declarations are actually &lt;i&gt;for&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;Now one point to make at the start is that optional typing (checked by the VM) and optional &lt;i&gt;static&lt;/i&gt; typing (checked by the compiler) are different things, and it makes some sense to do the former before doing the latter. Once you have a syntax for optional typing, making it static is merely a question of figuring out how to get the compiler to do the type check, instead of the VM. This activity would then blend in with Python's general issue of "how can we move things to the compiler to save run-time activity, without losing too much dynamism?"&lt;br /&gt;&lt;br /&gt;Having dropped the static idea for the moment, there's the fundamental question of what does a type declaration &lt;i&gt;mean&lt;/i&gt;? Python has historically relied on an approach that says "if it defines the right methods, it's OK by me". This is great for flexibility and code reuse, but plays merry hell with type inferencing systems, and can lead to some exceedingly cryptic error messages when you pass a type that doesn't provide the correct methods (or provides methods with the right names, but the wrong signatures, etc, etc).&lt;br /&gt;&lt;br /&gt;Stealing an example I like:&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace"&gt;&lt;br /&gt;def int_divide(x as Integer, y as Integer) as Integer:&lt;br /&gt;&amp;nbsp;&amp;nbsp;return x / y&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;We don't &lt;i&gt;really&lt;/i&gt; want &lt;font face="'Courier New',Courier,monospace"&gt;x as Integer&lt;/font&gt; (or &lt;font face="'Courier New',Courier,monospace"&gt;x : Integer&lt;/font&gt; in Guido's syntax) to mean &lt;font face="'Courier New',Courier,monospace"&gt;isinstance(x, Integer)&lt;/font&gt; do we? After all, we'd like this function to work for builtin types, and Python's builtin types won't know anything about this interface we have created. It would be far nicer if the optional typing was just a way of formalising the 'duck typing' that Python currently relies on.&lt;br /&gt;&lt;br /&gt;So let's consider something like the interfaces from PJE's PEAK, or Eiffel's idea of conformance (&lt;a href="http://www.python.org/peps/pep-0246.html"  target="_top"&gt;PEP 246&lt;/a&gt;, basically). In this case, we have a builtin method &lt;font face="'Courier New',Courier,monospace"&gt;adapt()&lt;/font&gt; to adapt a given object to a given protocol. I'd suggest the meaning of the example should become:&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace"&gt;&lt;br /&gt;def int_divide(x, y):&lt;br /&gt;&amp;nbsp;&amp;nbsp;x = adapt(x, Integer)&lt;br /&gt;&amp;nbsp;&amp;nbsp;y = adapt(y, Integer)&lt;br /&gt;&amp;nbsp;&amp;nbsp;return adapt(x / y, Integer)&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;Objects participate in this scheme as interfaces by definining &lt;font face="'Courier New',Courier,monospace"&gt;__adapt__&lt;/font&gt; special methods, and as adaptable objects by defining &lt;font face="'Courier New',Courier,monospace"&gt;__conform__&lt;/font&gt; special  methods. That way, interfaces and types can be written in any order, and still play well together. For instance, the existing 'adaptation methods' understood by the builtin objects' constructors (i.e. &lt;font face="'Courier New',Courier,monospace"&gt;__int__&lt;/font&gt;, &lt;font face="'Courier New',Courier,monospace"&gt;__str__&lt;/font&gt; and friends) could be incorporated into the system by having the &lt;font face="'Courier New',Courier,monospace"&gt;__adapt__&lt;/font&gt; methods of the relevant interfaces invoke the appropriate constructor - if the constructor throws an exception, then the adaptor method converts it to the appropriate adaptation exception.&lt;br /&gt;&lt;br /&gt;As mentioned in PEP 246, it would also be possible to have an 'adaptation registry' which mapped from (type, interface) tuples to adaptation methods. While this doesn't really matter to the basic idea of adaptation, it's handy for people trying to integrate code which provides the right interface, but doesn't actually provide the relevant adaptation information (e.g. if it provides a &lt;font face="'Courier New',Courier,monospace"&gt;read()&lt;/font&gt; method, and the function uses an interface which expects that method).&lt;br /&gt;&lt;br /&gt;For containers, it would make sense to have the interfaces be parameterisable (e.g. &lt;font face="'Courier New',Courier,monospace"&gt;List(Integer)&lt;/font&gt;, &lt;font face="'Courier New',Courier,monospace"&gt;List(Number)&lt;/font&gt;, &lt;font face="'Courier New',Courier,monospace"&gt;List(int, long)&lt;/font&gt; or &lt;font face="'Courier New',Courier,monospace"&gt;List()&lt;/font&gt; - that last example meaning, "allow a List with any types", since a list which allowed no types wouldn't be very useful). This suggests the concept of interface &lt;i&gt;factories&lt;/i&gt; - classes whose instances are themselves interfaces.&lt;br /&gt;&lt;br /&gt;For example (assume &lt;font face="'Courier New',Courier,monospace"&gt;AdaptationError&lt;/font&gt; is a subclass of &lt;font face="'Courier New',Courier,monospace"&gt;TypeError&lt;/font&gt; that is thrown when an adaptation fails):&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace"&gt;&lt;br /&gt;class AdaptedOk(Exception): pass&lt;br /&gt;&lt;br /&gt;class List(object):&lt;br /&gt;&amp;nbsp;&amp;nbsp;def __init__(self, *args):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self._allowed_interfaces = args&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;def __adapt__(self, obj):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lst = list(obj)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except Exception, ex:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise AdaptationError(str(ex))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;interfaces = self._allowed_interfaces&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if interfaces:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for i, x in enumerate(lst):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for interface in interfaces:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lst[i] = adapt(x, interface, None)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise AdaptedOk&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except AdaptationError:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;continue&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise AdaptationError("List element %s does not "&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;"support any allowed interface" % str(x))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except AdaptedOk:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pass&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return lst&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;def __eq__(self, other):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return (isinstance(other, type(self)) and&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(self._allowed_interfaces == other._allowed_interfaces))&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;OK, so PEP 246 combined with syntactic support would give a cleaner mechanism for &lt;i&gt;dynamic&lt;/i&gt; type checking. However, it would still be nice to have some sort of static checking for optimisation purposes (if the compiler &lt;i&gt;knows&lt;/i&gt; the types at compilation time, it can do all the operator lookups and so forth then, instead of waiting to do the lookups at runtime).&lt;br /&gt;&lt;br /&gt;Well, how about a slightly different pair of special methods: &lt;font face="'Courier New',Courier,monospace"&gt;__adapt_strict__&lt;/font&gt; and &lt;font face="'Courier New',Courier,monospace"&gt;__conform_strict__&lt;/font&gt;. The result of strict adaptation &lt;i&gt;guarantees&lt;/i&gt; that the result of adaptation is an actual instance of the interface. If an interface defines &lt;font face="'Courier New',Courier,monospace"&gt;__adapt_strict__&lt;/font&gt; without defining &lt;font face="'Courier New',Courier,monospace"&gt;__adapt__&lt;/font&gt;, then Python can be certain that the results of adaptation to that interface will be an instance of that interface.&lt;br /&gt;&lt;br /&gt;For example, the builtin types might provide &lt;font face="'Courier New',Courier,monospace"&gt;__adapt_strict__&lt;/font&gt; methods, allowing them to be used as interfaces which guaranteed that the result was an instance of the builtin type:&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace"&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;isinstance(adapt(x, int), int) # Always true&lt;br /&gt;&amp;nbsp;&amp;nbsp;isinstance(adapt(x, Integer), Integer) # Likely false&lt;br /&gt;&amp;nbsp;&amp;nbsp;isinstance(adapt(x, Integer), int) # Only possibly true&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;This can give us static typing, as long as the compiler can check for the existence of &lt;font face="'Courier New',Courier,monospace"&gt;__adapt__&lt;/font&gt; and &lt;font face="'Courier New',Courier,monospace"&gt;__adapt_strict__&lt;/font&gt; on the supplied interface (e.g. by assuming the names of builtins actually refer to the builtins). Here's some hypothetical implementations of  &lt;font face="'Courier New',Courier,monospace"&gt;__adapt_strict__&lt;/font&gt; for the builtins &lt;font face="'Courier New',Courier,monospace"&gt;object&lt;/font&gt; and &lt;font face="'Courier New',Courier,monospace"&gt;list&lt;/font&gt;:&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace"&gt;&lt;br /&gt;def object:&lt;br /&gt;&amp;nbsp;&amp;nbsp;# The rest of object's definition is as normal&lt;br /&gt;&amp;nbsp;&amp;nbsp;# Naturally this would really be implemented in C. . .&lt;br /&gt;&amp;nbsp;&amp;nbsp;# Use a class method so any new-style class&lt;br /&gt;&amp;nbsp;&amp;nbsp;# can automatically be used for strict adaptation&lt;br /&gt;&amp;nbsp;&amp;nbsp;@classmethod &lt;br /&gt;&amp;nbsp;&amp;nbsp;def __adapt_strict__(cls, obj):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if isinstance(obj, cls):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return obj&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result = cls(obj)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except Exception, ex:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise AdaptationError(str(ex))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return result&lt;br /&gt;&lt;br /&gt;class AdaptedOk(Exception): pass&lt;br /&gt;def list(object):&lt;br /&gt;&amp;nbsp;&amp;nbsp;# The rest of list's definition is as normal&lt;br /&gt;&amp;nbsp;&amp;nbsp;# Naturally this would really be implemented in C. . .&lt;br /&gt;&amp;nbsp;&amp;nbsp;# Uses an instance method, so we use self&lt;br /&gt;&amp;nbsp;&amp;nbsp;# to store the list of allowed interfaces&lt;br /&gt;&amp;nbsp;&amp;nbsp;def __adapt_strict__(self, obj):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lst = list(obj)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except Exception, ex:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise AdaptationError(str(ex))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if self:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for i, x in enumerate(lst):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for interface in self:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lst[i] = adapt(x, interface, None)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise AdaptedOk&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except AdaptationError:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;continue&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;raise AdaptationError("List element %s does not "&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;"support any allowed interface" % str(x))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except AdaptedOk:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pass&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return lst&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;With strict adaptation available, our earlier example of non-strict list adaptation would change to be:&lt;br /&gt;&lt;font face="'Courier New',Courier,monospace"&gt;&lt;br /&gt;def List(list):&lt;br /&gt;&amp;nbsp;&amp;nbsp;def __adapt__(self, obj):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return self.__adapt_strict__(obj)&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;The rules for adaptation would change slightly from those suggested in the PEP:&lt;ol&gt;&lt;li&gt;If the object is an exact instance of the interface, return it&lt;br /&gt;&lt;li&gt;Try the object's &lt;font face="'Courier New',Courier,monospace"&gt;__conform_strict__&lt;/font&gt; method, if it has one. If that works, return the result.&lt;br /&gt;&lt;li&gt;If the interface allows non-strict adaptation (it defines __adapt__), then try the object's &lt;font face="'Courier New',Courier,monospace"&gt;__conform__&lt;/font&gt; method, if it has one. If that works, return the result.&lt;br /&gt;&lt;li&gt;Try the interface's &lt;font face="'Courier New',Courier,monospace"&gt;__adapt_strict__&lt;/font&gt; method, if it has one. If that works, return the result.&lt;br /&gt;&lt;li&gt;Try the interface's &lt;font face="'Courier New',Courier,monospace"&gt;__adapt__&lt;/font&gt; method, if it has one. If that works, return the result.&lt;/ol&gt;&lt;br /&gt;The new additions are steps 2 &amp; 4, and step 3 has been modified so that it is only tried if the interface implements &lt;font face="'Courier New',Courier,monospace"&gt;__adapt__&lt;/font&gt;. The idea of restricting step 1 to exact instances is taken from the PEP - it allows subclasses to say "I don't implement my parent's interface" by throwing an exception in its conformation method. The check for instances of subclasses has been moved to the implementation of &lt;font face="'Courier New',Courier,monospace"&gt;object.__adapt_strict__&lt;/font&gt;. This allows interfaces to decide how they choose to deal with subclasses.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9320223-110387989393663651?l=boredomandlaziness.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://boredomandlaziness.blogspot.com/feeds/110387989393663651/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9320223&amp;postID=110387989393663651' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/110387989393663651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/110387989393663651'/><link rel='alternate' type='text/html' href='http://boredomandlaziness.blogspot.com/2004/12/type-checking-in-python.html' title='Type-checking in Python'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06437087323095993816'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9320223.post-110371407812921043</id><published>2004-12-22T21:14:00.000+10:00</published><updated>2004-12-22T21:14:38.130+10:00</updated><title type='text'>Google Footprint</title><content type='html'>OK, so here's the thing. In the real world, most Australians talking about 'Nick Coghlan' are going to be talking about the guy on Secret Life of Us. If not him, then the surfer from somewhere down south. If we went to Canada, well, there's a diplomat by that name, so at least a few people would know who he is, or would have seen an article or two about him.&lt;br /&gt;&lt;br /&gt;Enter the world of Google, though, and an awful lot of it is about me. On the first two pages of a search for "Nick Coghlan", there's just one entry halfway down the second page for the Canadian guy. The other two don't show up until the third page. The results are skewed massively in my favour because of the public mailing list web archives that Google indexes - and every one of my messages to those lists includes my name.&lt;br /&gt;&lt;br /&gt;You can really see the effect of this by searching for "Nicholas Coghlan" instead. I disappear from the results, and the TV actor and the Canadian diplomat take control of the show. I don't show up until page 4, on an old announcement from UQ. As you might guess from that, I don't use my full first name very often.&lt;br /&gt;&lt;br /&gt;Another interesting search is "nick coghlan -python -cygwin -software". The results are then quite similar to the "nicholas coghlan" results.&lt;br /&gt;&lt;br /&gt;Anyway, I guess my only real observation is that, when searching just for names, Google gives extremely high weight to participation in public online communities. Obvious, one might say, but it's an interesting limitation when looking for information on more famous people that happen to share a name with someone like me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9320223-110371407812921043?l=boredomandlaziness.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://boredomandlaziness.blogspot.com/feeds/110371407812921043/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9320223&amp;postID=110371407812921043' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/110371407812921043'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/110371407812921043'/><link rel='alternate' type='text/html' href='http://boredomandlaziness.blogspot.com/2004/12/google-footprint.html' title='Google Footprint'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06437087323095993816'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9320223.post-110232665382312547</id><published>2004-12-06T19:50:00.000+10:00</published><updated>2004-12-06T19:50:53.823+10:00</updated><title type='text'>Brain Dead Software #1: Yast Online Update</title><content type='html'>Suppose a new employee came to work for you. They're asked to collect 20 items from the company warehouse. You come back at the end of the day to find they have retrieved only one of the items. When queried, they say, "Well, the warheouse didn't have the second item on the list, so I came back to see what you wanted to do about it." "OK, fine, where are the other 18 items, then?" "Oh, I didn't try to get those. I needed to ask you about the second item, so I came back here." You'd be justifiably pissed off, and they'd probably be well on their way to getting fired.&lt;br /&gt;&lt;br /&gt;Yast Online Update is that employee. If it encounters a problem with any of the packages you ask it to install, it sits there with a freaking dialog box on the screen doing absolutely &lt;b&gt;nothing&lt;/b&gt; until you come back and tell it, "Look, just get on with the rest of the downloads already".&lt;br /&gt;&lt;br /&gt;To be fair, this problem isn't specific to YOU - YOU just happens to be the most recent example I've encountered. When a computer program is given a list of tasks to do, and encounters a problem with one of them, it should look at the list and continue on with as many of the remaining tasks as it can. At the end, it can present a report detailing any problems encountered, and asking what is to be done about each of them. With Brain Dead Software like YOU, I can't just leave it to run overnight - chances are it will only do useful work for a short while before some glitch causes it to twiddle its thumbs for the rest of the night, waiting for me to wake up and reassure it that everything is fine.&lt;br /&gt;&lt;br /&gt;Anyway, that's Brain Dead Software - programs that do things that would get a human fired. I'm sure there'll be more entries in this category.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9320223-110232665382312547?l=boredomandlaziness.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://boredomandlaziness.blogspot.com/feeds/110232665382312547/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9320223&amp;postID=110232665382312547' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/110232665382312547'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/110232665382312547'/><link rel='alternate' type='text/html' href='http://boredomandlaziness.blogspot.com/2004/12/brain-dead-software-1-yast-online.html' title='Brain Dead Software #1: Yast Online Update'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06437087323095993816'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9320223.post-110148046676963753</id><published>2004-11-27T00:47:00.000+10:00</published><updated>2004-12-30T21:51:42.323+10:00</updated><title type='text'>Mt St Helens</title><content type='html'>When I was in the US, one of the most impressive things I saw was the area around Mt St Helens. It was one of those things that made me glad my digital camera makes it so easy to take panoramic shots (click the panoramics to see slightly larger versions. If you want actual prints of any photos I post, let me know, since the originals have much better resolution than the versions I post).&lt;br /&gt;&lt;br /&gt;The river valley downstream from the mountain:&lt;br /&gt;&lt;a href="http://boredomandlaziness.skystorm.net/images/123-376_381_ST.jpg" target="_top"&gt;&lt;img src="http://members.iinet.net.au/~ncoghlan/boredomandlaziness/images/123-376_381_ST.jpg" width="357" height="63" alt="" border="0"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The view from the interpretative centre:&lt;br /&gt;&lt;a href="http://boredomandlaziness.skystorm.net/images/123-384_389_ST.jpg" target="_top"&gt;&lt;img src="http://members.iinet.net.au/~ncoghlan/boredomandlaziness/images/123-384_389_ST.jpg" width="361" height="61" alt="" border="0"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Heading around the back of the ridge:&lt;br /&gt;&lt;a href="http://boredomandlaziness.skystorm.net/images/123-392_398_ST.jpg" target="_top"&gt;&lt;img src="http://members.iinet.net.au/~ncoghlan/boredomandlaziness/images/123-392_398_ST.jpg" width="387" height="49" alt="" border="0"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Looking back towards the next ridge:&lt;br /&gt;&lt;a href="http://boredomandlaziness.skystorm.net/images/124-401_408_ST.jpg" target="_top"&gt;&lt;img src="http://members.iinet.net.au/~ncoghlan/boredomandlaziness/images/124-401_408_ST.jpg" width="429" height="61" alt="" border="0"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And here we have Leung making an appearance (Leung is the mascot I took with me on my trip. He's a little big to make a great photo mascot, so there are long stretches of photos where he doesn't appear). Anyway, the real point of this photo is the effect of the lateral blast from the eruption. Most of the grey stuff on the ridgeline is actually dead trees that were knocked over by the blast. You can see a bunch of trunks still standing where they were sheltered by the ridgeline.&lt;br /&gt;&lt;a href="http://boredomandlaziness.skystorm.net/images/124-414_IMG.jpg" target="_top"&gt;&lt;img src="http://members.iinet.net.au/~ncoghlan/boredomandlaziness/images/124-414_IMG.jpg" width="400" height="300" alt="" border="0"&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9320223-110148046676963753?l=boredomandlaziness.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://boredomandlaziness.blogspot.com/feeds/110148046676963753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9320223&amp;postID=110148046676963753' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/110148046676963753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/110148046676963753'/><link rel='alternate' type='text/html' href='http://boredomandlaziness.blogspot.com/2004/11/mt-st-helens.html' title='Mt St Helens'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06437087323095993816'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9320223.post-110147955310745741</id><published>2004-11-27T00:32:00.000+10:00</published><updated>2004-11-27T01:22:42.846+10:00</updated><title type='text'>Python Quirk</title><content type='html'>Python's a very nice language to program in, but it does have a few quirks. Normally, if you put multiple strings in your code, Python will automatically combine them into a single string.&lt;br /&gt;&lt;br /&gt;However, it *doesn't* do this if your string literals are positioned in the "docstring" location for a class or function. If they are then only the first string will be used as the docstring - the remainder will be ignored.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update:&lt;/b&gt; A quick discussion on python-dev showed that the behaviour was fairly easily explained. The string literal concatenation magic only works inside a single expression (e.g. an assignment statement). Two string literals on separate lines look like two distinct statements to the interpreter. Escaping the newline after the first literal causes the string concatenation behaviour to be applied.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9320223-110147955310745741?l=boredomandlaziness.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://boredomandlaziness.blogspot.com/feeds/110147955310745741/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9320223&amp;postID=110147955310745741' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/110147955310745741'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/110147955310745741'/><link rel='alternate' type='text/html' href='http://boredomandlaziness.blogspot.com/2004/11/python-quirk.html' title='Python Quirk'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06437087323095993816'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9320223.post-110138452072615065</id><published>2004-11-25T22:03:00.000+10:00</published><updated>2004-11-26T00:32:59.690+10:00</updated><title type='text'>Firing it up</title><content type='html'>So, I occasionally post stuff over at &lt;a href="http://www.talkinboutstuff.net" target="_top"&gt;Talkinboutstuff&lt;/a&gt;. However, that's mostly for random crap I expect the rest of the guys to find interesting/annoying/whatever.&lt;br /&gt;&lt;br /&gt;So, I created this extra blog for myself - somewhere to pontificate about things I &lt;i&gt;don't&lt;/i&gt; expect them to find interesting, like software and Python and open source and what have you. And, anything of interest to them can be cross-linked quite happily :)&lt;br /&gt;&lt;br /&gt;Maybe I'll even get around to attaching this thing to a real domain name!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9320223-110138452072615065?l=boredomandlaziness.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://boredomandlaziness.blogspot.com/feeds/110138452072615065/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9320223&amp;postID=110138452072615065' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/110138452072615065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9320223/posts/default/110138452072615065'/><link rel='alternate' type='text/html' href='http://boredomandlaziness.blogspot.com/2004/11/firing-it-up.html' title='Firing it up'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06437087323095993816'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry></feed>