{"id":104,"date":"2010-05-19T17:34:33","date_gmt":"2010-05-19T22:34:33","guid":{"rendered":"http:\/\/sam.tregar.com\/blog\/?p=104"},"modified":"2010-05-19T17:34:33","modified_gmt":"2010-05-19T22:34:33","slug":"python-makes-me-say-god-damn","status":"publish","type":"post","link":"http:\/\/sam.tregar.com\/blog\/2010\/05\/19\/python-makes-me-say-god-damn\/","title":{"rendered":"Python Makes Me Say God Damn"},"content":{"rendered":"<p>I&#8217;ve been coding in Python now for almost a year.  Mostly it&#8217;s been great fun, but a few things continue to annoy me.  Most of them are just a matter of taste, some related to my background as a Perl coder no doubt.  In any case, I&#8217;m hoping writing about them will help me be mindful and might bring up some useful workarounds in response.  And ranting is really its own reward.<\/p>\n<p><b>NOTE:<\/b> before you tell me I&#8217;m an idiot and Python is awesome, allow me to remind you that I like coding in Python and I&#8217;m quite sure I could produce a list like this for any language I&#8217;ve worked in.  So, yes, Python is awesome <i>and<\/i> Python sucks.  I&#8217;m sorry if I just blew your mind.<\/p>\n<p>In no particular order:<\/p>\n<p><b>The range() function is non-inclusive of the second term.<\/b>  If I say to you, give me the numbers from 1 to 5 are you going to say &#8220;1, 2, 3, 4&#8221;?  Of course not.  Even worse, Perl has trained me to expect inclusive ranges with the .. operator.  So I constantly stub my toe on Python&#8217;s range().  It can lead to nasty bugs &#8211; sometimes counting one less than expected is obvious, and sometimes it isn&#8217;t!<\/p>\n<p><b>I never know where to look for a method.<\/b>  Let&#8217;s say I&#8217;m having a hard time figuring out how to use some.awesome.Module&#8217;s foobar() method.  I&#8217;ve checked the doc-string and it&#8217;s not helping, I need to use the source.  At this point I&#8217;ve pretty much stopped trying to guess where it could be &#8211; I go straight to <a href=\"http:\/\/betterthangrep.com\/\">ack<\/a> and start searching the tree under some\/.  It could be in some.py, some\/__init__.py, some\/awesome.py, some\/awesome\/__init__.py, etc.  And if it&#8217;s a method with a common name &#8211; save(), for example &#8211; it can be very hard to figure out which save() is actually the one I&#8217;m looking for.<\/p>\n<p><b>Python is happy to do nothing.<\/b>  Consider this code:<\/p>\n<p>[sourcecode language=&#8221;python&#8221;]<br \/>\nfoo = range(1,100)<br \/>\nwhile len(foo) > 10:<br \/>\n    foo.pop<br \/>\n[\/sourcecode]<\/p>\n<p>It&#8217;s supposed to reduce foo until it&#8217;s got 10 elements (there are easier ways to do this, of course &#8211; not the point).  Actually it loops forever because foo.pop is actually a reference to the pop method.  To call it you must include parens:<\/p>\n<p>[sourcecode language=&#8221;python&#8221;]<br \/>\nfoo = range(1,100)<br \/>\nwhile len(foo) > 10:<br \/>\n    foo.pop()<br \/>\n[\/sourcecode]<\/p>\n<p>It makes a lot of sense to me that this is the way it is.  But couldn&#8217;t Python emit a warning when I do this?  The code does absolutely nothing useful &#8211; the method reference is returned and immediately discarded.  Perl does handle this case, emitting a warning about the use of a scalar in void context.  I never thought I&#8217;d miss that warning, but now I do!<\/p>\n<p><b>Strings are sequence types.<\/b>  At first glance this probably seems pretty harmless &#8211; you can iterate over the characters in a string.  Probably useful, right?  Well, not for me!  I honestly can&#8217;t remember the last time I intentionally iterated over a string character by character in a language other than C.  If I want to search a string I&#8217;ll use a regular expression or a call to index()\/find() &#8211; faster and easier.  So why does it irritate me?  It leads to bugs, because it&#8217;s all too easy to accidentally put a string where a list should go and Python will then happily iterate over the string.  For example, check out this bug (simplified a bit from the actual usage):<\/p>\n<p>[sourcecode language=&#8221;python&#8221;]<br \/>\n    for name, value in request.GET.items():<br \/>\n        params[name] = value[0]<br \/>\n[\/sourcecode]<\/p>\n<p>The bug here is that value is a string, not an array of values.  This bug resulted in each GET param getting truncated to a single character.  And it completely escaped my attention because I tested it with parameters that were small numbers &#8211; 0, 1 and 5.  So it got into live code that then failed when &#8220;2010-01-01&#8221; became &#8220;2&#8221;.  So lame.  I&#8217;d much rather Python said something useful like &#8220;You can&#8217;t index into a string dummy!&#8221;<\/p>\n<p><b>Unicode support is a mess.<\/b>  This one really surprised me.  I always thought Unicode in Perl was exceptionally bad, likely because it was always a second-class citizen.  I thought for some reason that Python would have a better, saner system.  Well, sadly no.  In fact, it has pretty much all the same problems that Perl has.  Consider this very common code:<\/p>\n<p>[sourcecode language=&#8221;text&#8221;]<br \/>\nbody=&#8221;&#8221;&#8221;<br \/>\nYour mailing template for mailing %s has a syntax error:<\/p>\n<p>    %s<\/p>\n<p>&#8220;&#8221;&#8221; % ( mailing.id, exception)<br \/>\n[\/sourcecode]<\/p>\n<p>That&#8217;s the buggy version.  It fails when the exception contains a non-ASCII character.  There&#8217;s no way you can predict when this will be the case &#8211; if you could predict bugs that result in exceptions they wouldn&#8217;t be nearly as much fun, now would they?  Here&#8217;s the fixed version:<\/p>\n<p>[sourcecode language=&#8221;text&#8221;]<br \/>\nbody=u&#8221;&#8221;&#8221;<br \/>\nYour mailing template for mailing %s has a syntax error:<\/p>\n<p>    %s<\/p>\n<p>&#8220;&#8221;&#8221; % ( mailing.id, exception)<br \/>\n[\/sourcecode]<\/p>\n<p>Did you spot the difference between code that works great and code that will make you hate yourself when it fails to show you a simple exception?  It&#8217;s a single &#8216;u&#8217; in front of the string quotes.  You, the Python programmer, are supposed to remember to put that character in front of strings that could someday contain an object with non-ASCII data in it (straight-up unicode strings work by magic, <a href=\"http:\/\/stackoverflow.com\/questions\/2867773\/why-does-python-sometimes-upgrade-a-string-to-unicode-and-sometimes-not\">see here for details<\/a>).  You&#8217;re supposed to figure it out and tell Python because for some reason upgrading the string at runtime would be the wrong thing to do.  Please, shoot me now.<\/p>\n<p>Actually, just wait, you can shoot me the next time I have to debug a random Unicode failure in our code-base.  They pop up regularly when some object that nobody thought could have non-ASCII in it happens to get a non-ASCII character.  Obviously better testing would help, but some things, like the contents of exceptions, are pretty hard to predict!<\/p>\n<p>So that&#8217;s my list &#8211; got one of your own?  There&#8217;s nothing like a good rant, go for it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve been coding in Python now for almost a year. Mostly it&#8217;s been great fun, but a few things continue to annoy me. Most of them are just a matter of taste, some related to my background as a Perl coder no doubt. In any case, I&#8217;m hoping writing about them will help me be [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-104","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"http:\/\/sam.tregar.com\/blog\/wp-json\/wp\/v2\/posts\/104","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/sam.tregar.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/sam.tregar.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/sam.tregar.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/sam.tregar.com\/blog\/wp-json\/wp\/v2\/comments?post=104"}],"version-history":[{"count":43,"href":"http:\/\/sam.tregar.com\/blog\/wp-json\/wp\/v2\/posts\/104\/revisions"}],"predecessor-version":[{"id":177,"href":"http:\/\/sam.tregar.com\/blog\/wp-json\/wp\/v2\/posts\/104\/revisions\/177"}],"wp:attachment":[{"href":"http:\/\/sam.tregar.com\/blog\/wp-json\/wp\/v2\/media?parent=104"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/sam.tregar.com\/blog\/wp-json\/wp\/v2\/categories?post=104"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/sam.tregar.com\/blog\/wp-json\/wp\/v2\/tags?post=104"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}