tag:blogger.com,1999:blog-60542563604963376082024-02-20T11:03:58.336-08:00EngyrusPython programming, technical writing, and related effluvia.Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.comBlogger21125tag:blogger.com,1999:blog-6054256360496337608.post-45900139838269569152023-12-08T14:50:00.000-08:002023-12-14T05:17:03.767-08:00Creating and Solving Spelling Bee Puzzles in Python<p> I enjoy playing the New York Times' game <a href="https://www.nytimes.com/puzzles/spelling-bee">Spelling Bee</a>. I wondered about how to write a Python script that creates and solves Spelling Bee puzzles and decided to take a stab at it.</p><p>For those who aren't familiar, each puzzle is built on a seed word containing exactly seven unique letters. These are randomly arranged in a hexagon format resembling a honeycomb. You make words at least four letters long from these letters (you can use letters more than once) and the puzzle judges them as real words or not. One letter is placed in the center of the puzzle and must appear in all words. The words are scored based on their lengths and the game designates you as a genius (or lesser skill levels) based on your score. Every puzzle has one or more <i>pangrams</i> that use all the letters in the puzzle at least once (one is the seed word although there can be more).</p><p>It turns out you don't need much code at all to generate a puzzle that meets the criteria. Given a list of English words, you can easily identify all the ones that could be a seed word (contain only letters and have exactly seven of unique ones). Then you can either pick one at random or ask the user to enter one (making sure it qualifies) as the seed for a puzzle.</p><p>Most Unix-like systems have a word list at /usr/share/dict/words. This list exists on Mac OS X, so I've used it. The list does have a flaw: it's much bigger than the one the New York Times uses. (I've often been surprised by the words that aren't recognized by the official Spelling Bee puzzle.) This means that not only will the solution set be somewhat different from the Times' answers, you'll see a number of obscure and naughty words that you'd never see in theirs. No big deal, it'll work with any word list so you can substitute whatever you want. Exercise for the reader and all that.</p><p>The basic approach I took is:</p><p></p><ol style="text-align: left;"><li>Read all the words into a list. Make a second list containing only the words that could be seed words (exactly seven unique letters).</li><li>Ask the user to select a seed word or allow the script to choose one randomly. If the user enters one, it is validated against the seed word list. If the user allows the script to choose one, they're further asked for a sequence of letters that should appear in the seed (I have noticed that puzzles often contain "ing" or another sequence of letters that constrains the solutions, so I added the ability to do that, if you want).</li><ul><li>The user may also just enter a string of 7 unique letters that are not a word. (You might have this instead of the actual seed word if you are trying to solve an existing puzzle.) The script will find the first pangram made of those letters and use that as the seed word.</li></ul><li>Ask the user to choose which letter should be in the center of the puzzle, or again choose it randomly.</li><li>Find all the words in the word list that are solutions to the puzzle. These are the ones that are at least four letters long, contain only letters from the seed word, and contain the center letter.</li></ol><p></p><p>The script can be used either to generate puzzles (by finding good seed words, trying to solve, then checking your answers) or to help solve a puzzle, including the ones in the Times.</p><p>You could expand it into an actual game that you can play, with a GUI and all that, but I'll leave that for you. Here's the code.</p><div><div><div><div><span style="font-family: courier; font-size: x-small;"># bee.py - using UNIX word list, create a puzzle like the New York Times' </span></div><div><span style="font-family: courier; font-size: x-small;"># "Spelling Bee," along with all possible solutions</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"># The UNIX word list is more extensive than the Times' list; you'll see</span></div><div><span style="font-family: courier; font-size: x-small;"># some mighty obscure words, and also some totally inappropriate ones.</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">import random, itertools</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;">all_words = open("/usr/share/dict/words").read().splitlines()</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"># read potential seed words: at least 7 unique letters and no uppercase or punctuation</span></div><div><span style="font-family: courier; font-size: x-small;">seed_words = [word for word in all_words if len(word) > 6 and word.isalpha() and </span></div><div><span style="font-family: courier; font-size: x-small;"> len(set(word)) == 7 and word.lower() == word]</span></div><div><span style="font-family: courier; font-size: x-small;">print(len(seed_words), "seed words")</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"># get or randomly choose seed word for puzzle</span></div><div><span style="font-family: courier; font-size: x-small;">seed_word = ""</span></div><div><span style="font-family: courier; font-size: x-small;">while seed_word not in seed_words:</span></div><div><span style="font-family: courier; font-size: x-small;"> seed_word = input("seed word, exactly 7 unique letters (enter for random): " ).lower()</span></div><div><span style="font-family: courier; font-size: x-small;"> if seed_word == "":</span></div><div><span style="font-family: courier; font-size: x-small;"> required_letters = input(</span></div><div><span style="font-family: courier; font-size: x-small;"> "... substring the random word must contain: ").lower()</span></div><div><span style="font-family: courier; font-size: x-small;"> seed_word = random.choice(seed_words)</span></div><div><span style="font-family: courier; font-size: x-small;"> while required_letters != "" and required_letters not in seed_word:</span></div><div><span style="font-family: courier; font-size: x-small;"> seed_word = random.choice(seed_words)</span></div><div><span style="font-family: courier; font-size: x-small;"> print("seed word:", seed_word.upper())</span></div><div><span style="font-family: courier; font-size: x-small;"> else:</span></div><div><span style="font-family: courier; font-size: x-small;"> # the user entered a word but it is not a seed word</span></div><div><span style="font-family: courier; font-size: x-small;"> if seed_word not in seed_words:</span></div><div><span style="font-family: courier; font-size: x-small;"> seed_word = set(seed_word.lower())</span></div><div><span style="font-family: courier; font-size: x-small;"> if len(seed_word) == 7:</span></div><div><span style="font-family: courier; font-size: x-small;"> seed_word = min(itertools.chain((word for word in seed_words if set(word) == seed_word), ""), key=len)</span></div><div><span style="font-family: courier; font-size: x-small;"> if seed_word:</span></div><div><span style="font-family: courier; font-size: x-small;"> print("seed word:", seed_word.upper())</span></div><div><span style="font-family: courier; font-size: x-small;"> else:</span></div><div><span style="font-family: courier; font-size: x-small;"> seed_word = ""</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"># get or choose center letter for puzzle.</span></div><div><span style="font-family: courier; font-size: x-small;"># this letter must appear in all answers</span></div><div><span style="font-family: courier; font-size: x-small;">seed_letters = set(seed_word)</span></div><div><span style="font-family: courier; font-size: x-small;">center_letter = ""</span></div><div><span style="font-family: courier; font-size: x-small;">while len(center_letter) != 1 or center_letter not in seed_letters:</span></div><div><span style="font-family: courier; font-size: x-small;"> center_letter = input("center letter (enter for random): ").lower()</span></div><div><span style="font-family: courier; font-size: x-small;"> if center_letter == "":</span></div><div><span style="font-family: courier; font-size: x-small;"> center_letter = random.choice(seed_word)</span></div><div><span style="font-family: courier; font-size: x-small;"> print("center letter:", center_letter.upper())</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"># print puzzle, randomized but withcenter letter in middle</span></div><div><span style="font-family: courier; font-size: x-small;">puzzle_letters = list(set(seed_word.upper()))</span></div><div><span style="font-family: courier; font-size: x-small;">random.shuffle(puzzle_letters)</span></div><div><span style="font-family: courier; font-size: x-small;"># put the center letter in the center</span></div><div><span style="font-family: courier; font-size: x-small;">center_index = puzzle_letters.index(center_letter.upper())</span></div><div><span style="font-family: courier; font-size: x-small;">puzzle_letters[center_index], puzzle_letters[3] = puzzle_letters[3], puzzle_letters[center_index]</span></div><div><span style="font-family: courier; font-size: x-small;">print("puzzle: {0} {1}\n {2} {3} {4}\n {5} {6}".format(*puzzle_letters))</span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"># generate solution words. print with pangrams in caps</span></div><div><span style="font-family: courier; font-size: x-small;">solution_words = [word for word in all_words if len(word) > 3 and center_letter in word </span></div><div><span style="font-family: courier; font-size: x-small;"> and not set(word).difference(seed_word)]</span></div><div><span style="font-family: courier; font-size: x-small;">print(len(solution_words), "solution words:", sorted(</span></div><div><span style="font-family: courier; font-size: x-small;"> word.upper() if len(set(word)) == 7 else word for word in solution_words))</span></div></div></div></div><div><br /></div>Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com0tag:blogger.com,1999:blog-6054256360496337608.post-56350536354182264192021-12-16T11:36:00.002-08:002021-12-16T11:36:43.135-08:00SPT #5: The endless print<p><i> The blog roars back to life; with a hiss and a clank, suddenly a new Stupid Python Trick appears!</i></p><p>This one's a quickie. Python`s <span style="font-family: courier;">print()</span> function takes an <span style="font-family: courier;">end</span> argument that lets you change what gets printed after the rest of things in that call have been printed. By default, this is a newline. It's common to set this to an empty string to suppress the newline:</p><p><span style="font-family: courier;">print("There is no newline", end="")</span></p><p>But you can do the same by just including what you want to print <i>as the <span style="font-family: courier;">end</span> argument.</i></p><p><span style="font-family: courier;">print(end="There is no newline")</span></p><p>By my count, that saves us four whole keystrokes: two quotes, a comma, and a space! Are we feeling stupid yet?<br /></p>Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com0tag:blogger.com,1999:blog-6054256360496337608.post-33570786321342805302016-05-16T20:53:00.004-07:002016-05-16T20:56:09.933-07:00Release: AutoRemote Push (Unofficial)To learn some new stuff and sharpen my JavaScript saw, I've developed my first Firefox add-on. It's called AutoRemote Push (Unofficial) and it's useful for people who want to send links from Firefox to their Android device using João Dias's AutoRemote app.<br />
<br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/autoremote-push-unofficial/" target="_blank">Install it here</a><br />
<br />
<a href="https://github.com/engyrus/unofficial-autoremote-push" target="_blank">Source code here</a>Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com1tag:blogger.com,1999:blog-6054256360496337608.post-30214065603041863132015-04-09T14:48:00.000-07:002016-05-06T13:22:41.051-07:00SJST #1: Multiline string literals<i>I've recently been doing some JavaScript programming for the Welcome Screen feature included with some of our products. The Welcome Screen is a QWebView: basically a complete Web browser embedded in the application. The Welcome Screen itself is a mini Web application implemented using HTML, CSS, and JavaScript. So here's Stupid JavaScript Tricks #1, which presents an awful hack to simulate multi-line string literals in JavaScript. As usual, programmer beware.</i><br />
<br />
The more I work with JavaScript, the more I appreciate Python, which, by comparison, is a quite thoughtfully-designed programming language. One of the things that's very convenient about Python is its ability to construct multiple-line string literals using triple quote marks:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">haiku = """</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Triple quoted strings</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Programmer's able helper</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">When writing poems</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">"""</span><br />
<br />
If you need to embed HTML, or CSS, or a shell script, or some test data, or really anything else that contains newlines, in your Python code, you can easily see how this would be useful. It's significantly more readable, and more maintainable, than cramming that all into a single line with <span style="font-family: "courier new" , "courier" , monospace;">\n</span> escapes in it, or using a syntax-heavy workaround like defining a list and then joining it.<br />
<br />
Python's designers were so thoughtful that they even allow the use of triple <i>single</i> quotes on the off chance that your string literal happens to contain three <i>double</i> quote marks in a row. (Who knows, maybe you've embedded some Python code with multi-line string literals of its own! Which is a bad idea, generally, but hey.)<br />
<br />
Now, think of a programming language that is used quite frequently for Web applications, in which you can easily imagine you might find yourself with a need to represent decently-sized snippets of HTML and/or CSS, and try to guess what feature it <i>doesn't</i> have.<br />
<br />
That's right. JavaScript does not have decent syntax for multi-line string literals. Well, that's not quite true; ECMAScript 6 (a language standard for JavaScript) allows the definition of template strings using backticks (<span style="font-family: "courier new" , "courier" , monospace;">`</span>)<i>.</i> However, the ECMAScript 6 standard is only a couple years old, which means you might not be able to use it depending on what browsers you need to support. In my use case, it isn't supported by the version of WebKit provided by the version of Qt we're using in our applications.<br />
<br />
So... skanky hack to the rescue. It turns out that JavaScript can easily convert pretty much any object into some sort of string representation. The string representation of a function is the <i>function's source code.</i> That's pretty handy when debugging, and it'd be nice if we didn't have to use the <span style="font-family: "courier new" , "courier" , monospace;">inspect</span> module with Python to get the same thing (if we're lucky and the function was defined in a source file). But I digress.<br />
<br />
By making the body of the function a big-ass comment using the C-style <span style="font-family: "courier new" , "courier" , monospace;">/* ... */</span> syntax, we can put whatever text we want into it—with line breaks wherever we need them, since line breaks are perfectly legal inside block comments. We can then get that function's text representation, nibble off the JavaScript function boilerplate, and end up with the string we want.<br />
<br />
Unfortunately, this will break if the text we want to represent contains <span style="font-family: "courier new" , "courier" , monospace;">*/</span> (which might be a problem with CSS if you ever put comments into your stylesheets, as they use this syntax, and JavaScript doesn't support nesting block comments). Inventing further kludgey workarounds for this is left as an exercise.<br />
<br />
Here's how such a "text definition" might look:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">var haiku = function() {/*</span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">A horrible hack!</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Is this much better than not </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Having it at all?</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">*/}.toString().slice(15, -3).trim();</span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">alert(haiku); </span><br />
<br />
Now, this works... unless you're stuck using the JavaScript version in our Welcome Screen, which doesn't allow method calls on function objects until they've been finalized. The upshot is we can't actually assign the string in a single statement; instead we must do this:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">var haiku = function() {/*</span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">A horrible hack!</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Is this much better than not </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Having it at all?</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">*/}</span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">haiku = haiku.toString();</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">haiku = haiku.slice(haiku.indexOf("/*")+2,</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> haiku.lastIndexOf("*/")).trim();</span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">alert(haiku); </span><br />
<br />
In this code we actually search for the comment delimiters rather than hard-coding their positions, which is something that bugged me about that initial version. Let's write a function to do it; then we can pass in an anonymous function defined right in the function call. (In Python we'd use it as a decorator using the <span style="font-family: "courier new" , "courier" , monospace;">@</span> syntax, but then, in Python we wouldn't have this problem to begin with.)<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">function multi(func) {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> t = func.toString();</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> return t.slice(t.indexOf("/*")+2, t.lastIndexOf("*/")).trim();</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">var haiku = multi(function() {/*</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">So many haiku!</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Or is it haikus? Don't care. </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">The cheese stands alone.</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">*/})</span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">alert(haiku); </span><br />
<br />
All right. So it's there, and it's stinky, and it works. Should you use it in your Web apps? Probably not. But let's not ever pretend we're all saints. Sometimes, you do what works.<br />
<br />Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com2tag:blogger.com,1999:blog-6054256360496337608.post-90313362040461499982015-03-03T10:18:00.002-08:002017-09-18T10:29:49.339-07:00SPT #4: There is no try<i>"Stupid Python Tricks" explores sexy ways to whip Python features until they beg for mercy. Stupid Python Tricks may well be fifty different shades of gray. Reader discretion is advised.</i><br />
<br />
I've recently been wishing that Python`s <span style="font-family: "courier new" , "courier" , monospace;">set</span> type had a method like <span style="font-family: "courier new" , "courier" , monospace;">add()</span> but which returned a Boolean indicating whether the item being added was already in the set. We could add this behavior to the <span style="font-family: "courier new" , "courier" , monospace;">add()</span> method without fear of breaking much code, since most uses will ignore the return value, but I'd rather keep <span style="font-family: "courier new" , "courier" , monospace;">add()</span> as fast as possible. So let's call this new method <span style="font-family: "courier new" , "courier" , monospace;">added()</span> and have it return <span style="font-family: "courier new" , "courier" , monospace;">True</span> if the item needed to be added, and <span style="font-family: "courier new" , "courier" , monospace;">False</span> otherwise. You can derive a new class from <span style="font-family: "courier new" , "courier" , monospace;">set</span>, so let's go ahead and do that:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">class Set(set):</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> def added(self, item):</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> result = item not in self # True if item needs to be added</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> self.add(item)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> return result</span><br />
<br />
Note our <span style="font-family: "courier new" , "courier" , monospace;">self.added()</span> here is not conditional in any way; it doesn't need to be. <span style="font-family: "courier new" , "courier" , monospace;">set.add()</span> is <i>idempotent:</i> adding the same item multiple times doesn't hurt anything, and it's actually faster to do the <span style="font-family: "courier new" , "courier" , monospace;">add()</span> even if it's not necessary (since that stays in the fast C implementation of the <span style="font-family: "courier new" , "courier" , monospace;">set</span> type) than to try to avoid the unnecessary <span style="font-family: "courier new" , "courier" , monospace;">add()</span> with an <span style="font-family: "courier new" , "courier" , monospace;">if</span> statement.<br />
<br />
Our new method is convenient for deduplicating lists while retaining the order of their items:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">pies = ["apple", "banana cream", "apple", "boysenberry",</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> "apple", "pumpkin", "banana cream"]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">seen = Set() # keeps track of pies we have already seen</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">pies[:] = (pie for pie in pies if seen.added(pie))</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">print(pies)</span><br />
<br />
Result: <span style="font-family: "courier new" , "courier" , monospace;">["apple", "banana cream", "boysenberry", "pumpkin"]</span><br />
<br />
Be right back; I'm hungry for pie now.<br />
<br />
OK. Our <span style="font-family: "courier new" , "courier" , monospace;">added()</span> method works fine. There's nothing wrong with it. But doesn't it seem a little... inelegant... to have to store the result of the set membership test in a local variable, add the new item, and finally return the value we previously squirreled away? Why can't we simply return the result, and <i>then</i> do the add? Because the <span style="font-family: "courier new" , "courier" , monospace;">return</span> ends the function's execution? Don't be silly; we won't let that stop us!<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">class Set(set):</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> def added(self, item):</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> try: return item not in self</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> finally: self.add(item)</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">N</span>ot only is this an unconventional use of <span style="font-family: "courier new" , "courier" , monospace;">try</span>, it's also a wee bit slower than our earlier version. And <i>that's</i> why we call it "Stupid Python Tricks." Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com9tag:blogger.com,1999:blog-6054256360496337608.post-19986026461574785782015-02-19T15:31:00.004-08:002015-03-23T16:53:58.489-07:00SPT #3: The constant singleton<i>"Stupid Python Tricks" explores ways to abuse Python features for the hell of it. Stupid Python Tricks may well be perpendicular to maintainability and sanity. Abandon all hope, ye who enter here.</i> <br />
<br />
Classes can be convenient namespaces for corralling related objects. You don't even need to instantiate such a class; you can just use the class itself, since attribute access works the same for classes and instances. (If you need methods in the namespaces, it is better to instantiate the class, since otherwise you need to decorate each method with <span style="font-family: "Courier New",Courier,monospace;">@classmethod</span>. But for data, it works great, and saves the step of instantiation.)<br />
<br />
One category of related objects that can be useful to put in a namespace are constants. You can even override <span style="font-family: "Courier New",Courier,monospace;">__setattr__</span> to slap the programmer's hand should he (or she) try to change those tempting attributes-what-should-be-constants. But disappointment lurks ahead... declaring <span style="font-family: "Courier New",Courier,monospace;">__setattr__</span> on a class won't actually override the behavior of setting the attribute on the class! See, for example, this:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">class Const(object):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> answer = 42 </span><br />
<span style="font-family: "Courier New",Courier,monospace;"> def __setattr__(self, name, value):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> raise TypeError("variables may vary, but constants never do")</span><br />
<br />
The intent here is to prevent the class attribute <span style="font-family: "Courier New",Courier,monospace;">answer</span> (or any other attribute, for that matter) from being set or changed. But it doesn't work:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"> Const.answer = 13 # no problem!</span><br />
<br />
It works only if we instantiate the class:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"> const = Const()</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> const.answer = 42 # TypeError</span><br />
<br />
One way to solve this is to just go ahead and instantiate the class right after we define it. We can even give the instance the same name as the class, a cheap way of making it a little more difficult to make additional instances (not that it would matter too much if someone did, aside from a little bit of memory overhead, and not like it's difficult to get the class's type even if it's not in a convenient namespace):<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"> Const = Const() </span><br />
<br />
But now suppose we want to write a base class that provides the behavior of denying attribute changes, so that we can write subclasses that hold our constant definitions. Now we've gotta instantiate each of them because the desired behavior isn't fully contained in the class itself. And if we forget, the constants aren't constant anymore! Ugh. What we need to do is somehow override the attribute-setting behavior of <i>the class itself.</i> How?<br />
<br />
Well, we know that to override attribute-setting behavior on an <i>instance</i>, we define <span style="font-family: "Courier New",Courier,monospace;">__setattr__</span> on its <i>class</i>. We also know that every Python class is itself an object, which implies that <i>a class is an instance of some other class.</i> So what we want to do is define <span style="font-family: "Courier New",Courier,monospace;">__setattr__</span> on the <i>class's class. </i><br />
<br />
A class's class is called its <i>metaclass.</i> Just as every ordinary instance is created from a class, so every class is an instance created from a metaclass. In Python, the default metaclass is a class called <span style="font-family: "Courier New",Courier,monospace;">type</span>, so to write our own metaclass, we must inherit from <span style="font-family: "Courier New",Courier,monospace;">type</span>.<br />
<br />
To sum up, we can override the attribute-setting behavior of our <span style="font-family: "Courier New",Courier,monospace;">Const</span> base class by writing a <span style="font-family: "Courier New",Courier,monospace;">__getattr__</span> method on a metaclass, then using that metaclass to define our base class. Metaclasses are inherited, so the behavior of our base class will carry over to any classes derived from it. Which is exactly what we want!<br />
<br />
While we're at it, we can also define what happens if someone tries to instantiate the class, by overriding the <span style="font-family: "Courier New",Courier,monospace;">__call__</span> method. The <span style="font-family: "Courier New",Courier,monospace;">__call__</span> method of <span style="font-family: "Courier New",Courier,monospace;">type</span> is what calls <span style="font-family: "Courier New",Courier,monospace;">__new__</span> and then <span style="font-family: "Courier New",Courier,monospace;">__init__</span> to construct the class. Since we're writing our own metaclass, we can make it do something different.<br />
<br />
What should trying to instantiate a class that's just being used as a namespace do? Maybe raise <span style="font-family: "Courier New",Courier,monospace;">TypeError</span>? Or, since someone who tries to instantiate the class is probably trying to get access to its attributes, just return the class itself (i.e., make the class a singleton, i.e., make the class its own instance, i.e., make instantiating the class a no-op)? This being <i>Stupid Python Tricks,</i> let's do <i>that!</i> (Also, it's less typing than raising a proper exception, although of course writing a sentence <i>explaining</i> that ruins the economy.)<br />
<i><br /></i>
<span style="font-family: "Courier New",Courier,monospace;"> class ConstMeta(type):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> def __setattr__(cls, name, value):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> raise TypeError("variables may vary, but constants never do")</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> def __call__(cls):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> return cls</span><br />
<br />
Now we can define a base class. (Python 2 and Python 3 have slightly different syntax for specifying the metaclass.)<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"> # Python 2 version</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> class Const(object):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> __metaclass__ = ConstMeta</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
<span style="font-family: "Courier New",Courier,monospace;"> # Python 3 version</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> class Const(metaclass=ConstMeta):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> pass</span><br />
<br />
Aaand <i>now </i>we can use that base class to define namespaces in which the attributes can't be modified:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"> class nums(Const):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> ANSWER = 42</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> FUN = 69</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> UNLUCKY = 13</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> PI = 3.1415927 # close enough </span><br />
<br />
Now let's try changing all circles to hexagons:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"> nums.PI = 3 # nope!</span><br />
<br />
You might next reasonably ask: how does the class get defined in the first place if its metaclass disallows putting attributes on it? And the answer is that defining an attribute in the body of a class definition doesn't call <span style="font-family: "Courier New",Courier,monospace;">__setattr__</span>! Instead, the attributes are placed in a dictionary, and when the class definition is complete, that dictionary becomes the class's <span style="font-family: "Courier New",Courier,monospace;">__dict__</span> attribute, where all its attributes are stored. Try it:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"> print (nums.__dict__.items())</span><br />
<br />
Now you might think that knowing about <span style="font-family: "Courier New",Courier,monospace;">__dict__</span> will let you modify these read-only attributes anyway, even though we've written a metaclass to prevent it. <i>Right?</i><br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"> nums.__dict__["FUN"] -= 1 # Right????</span><br />
<br />
But as it happens, the <span style="font-family: "Courier New",Courier,monospace;">__dict__</span> attribute of a class is not actually a Python <span style="font-family: "Courier New",Courier,monospace;">dict</span> object, but rather a proxy object that does not allow item assignment. Foiled! You might also think you could just use <span style="font-family: "Courier New",Courier,monospace;">object.__setattr__</span> ... but that doesn't work either! Foiled again!<br />
<br />
All right already... <span style="font-family: "Courier New",Courier,monospace;">type.__setattr__</span> does work:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"> # Deep Thought had an off-by-one error</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> type.__setattr__(nums, "ANSWER", 41)</span><br />
<br />
Of course, you could also just go with the nuclear option:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"> del ConstMeta.__setattr__ # <a href="https://www.youtube.com/watch?v=Ec-8A5k16Ak" target="_blank">kaboom</a></span><br />
<br />
Which goes to show you... even when you think you've put up a wall around something in Python, you really haven't. Ever. That's why Python's unofficial motto is "I'll show you mine if you show me yours." Whoops, I mean, "We're all consenting adults here."<br />
<br />
And now you know... the <i>rest </i>of the story.Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com3tag:blogger.com,1999:blog-6054256360496337608.post-85784767354306599632013-11-08T10:48:00.002-08:002013-11-19T13:28:32.431-08:00SPT #2: One global to rule them all<i>"Stupid Python Tricks" explores ways to abuse Python features for fun
and profit. Stupid Python Tricks may well be diametrically opposed to best practices. Don your peril-sensitive sunglasses before proceeding.</i><br />
<br />
You know how when you have a lot of globals and it's a pain to modify them, because you have to declare the globals you want to modify in each function using the <span style="font-family: "Courier New",Courier,monospace;">global</span> statement? Yeah, me neither. After all, globals are a poor programming practice! And I never engage in those...<br />
<br />
However, for educational porpoises, or at least didactic dolphins, here's a short hack that takes advantage of the fact that Python globals can be accessed, but not modified, without declaring them global. Basically, what we do is replace the built-in <span style="font-family: "Courier New",Courier,monospace;">globals() </span>function with an object that lets you read and set globals via attribute access. Instead of doing this:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">def my_func(a, b, c):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> global ans</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> ans = a + b + c</span><br />
<br />
You can instead do:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">import globals </span><br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">def my_func(a, b, c):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> globals.ans = a + b + c</span><br />
<br />
This works fine because you aren't re-binding any global names; instead, you are merely mutating an existing object. Or so Python believes... bwahahaha! While we didn't save any lines of code in this short example, imagine if we had dozens of functions that used globals. We'd save literally dozens of <span style="font-family: "Courier New",Courier,monospace;">global</span> statements! And we could dine on spaghetti code for weeks.<br />
<br />
Calling this object, i.e. <span style="font-family: "Courier New",Courier,monospace;">globals()</span>, continues to return the modules's globals dictionary, just like before, thanks to a <span style="font-family: "Courier New",Courier,monospace;">__call__()</span> method on the class.<br />
<br />
Without further ado, then, here's <span style="font-family: "Courier New",Courier,monospace;">globals.py</span>:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">from inspect import currentframe<br />from sys import modules<br /><br />class Globals(object):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /> def __getattribute__(self, key, currentframe=currentframe):<br /> try:<br /> return currentframe().f_back.f_globals[key]<br /> except KeyError:<br /> pass # if we raise NameError here we get 2 err msgs<br /> raise NameError("global name '%s' is not defined" % key)<br /> </span><br />
<span style="font-family: "Courier New",Courier,monospace;"> def __setattr__(self, key, value, currentframe=currentframe):<br /> currentframe().f_back.f_globals[key] = value<br /> </span><br />
<span style="font-family: "Courier New",Courier,monospace;"> def __call__(self, currentframe=currentframe):<br /> return currentframe().f_back.f_globals<br /><br />globals = Globals()<br />modules[__name__] = globals # so other modules will use it<br />import globals # make sure that worked</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
<span style="font-family: "Courier New",Courier,monospace;"># simple test</span><br />
<span style="font-family: "Courier New",Courier,monospace;">globals.answer = 42</span><br />
<span style="font-family: "Courier New",Courier,monospace;">assert globals.answer is answer</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
<br />
This short bit of code demonstrates more than one dirty, dirty hack. <span style="font-family: "Courier New",Courier,monospace;">inspect.currentframe()</span>
is used to allow us to manipulate the globals of the module
containing the function it's called from, rather than the globals of its
own module. We assign into <span style="font-family: "Courier New",Courier,monospace;">sys.modules</span> to replace the <span style="font-family: "Courier New",Courier,monospace;">globals</span> module object with our <span style="font-family: "Courier New",Courier,monospace;">Globals</span> class instance so that you only need <span style="font-family: "Courier New",Courier,monospace;">import globals</span>, not <span style="font-family: "Courier New",Courier,monospace;">from </span><span style="font-family: "Courier New",Courier,monospace;">globals import globals</span>. Since it's a functional replacement for the built-in <span style="font-family: "Courier New",Courier,monospace;">globals()</span> function, we could stick it into the <span style="font-family: "Courier New",Courier,monospace;">__builtins__</span> namespace so other modules would get it even without importing it, but even I have my limits!<br />
<br />Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com1tag:blogger.com,1999:blog-6054256360496337608.post-69797694554768341462013-03-18T11:31:00.002-07:002023-01-06T06:28:59.116-08:00IDTKAP #4: __debug__ and -OWayyyyy back in June 2012, I posted the <a href="http://www.engyrus.com/2012/06/spt-1-automatically-stripping-debug.html" target="_blank">first Stupid Python Trick</a>, showing a way to abuse the <span style="font-family: "Courier New",Courier,monospace;">assert </span>statement to write debug code that is completely stripped when you run Python using the <span style="font-family: "Courier New",Courier,monospace;">-O</span> flag to enable optimization.<br />
<br />
The <span style="font-family: "Courier New",Courier,monospace;">-O</span> flag is documented as removing <span style="font-family: "Courier New",Courier,monospace;">assert </span>instructions as though you never wrote them. But that's not all it does. It also sets a constant, <span style="font-family: "Courier New",Courier,monospace;">__debug__</span>, which is normally <span style="font-family: "Courier New",Courier,monospace;">True</span>, to <span style="font-family: "Courier New",Courier,monospace;">False</span>. The value of <span style="font-family: "Courier New",Courier,monospace;">__debug__</span> is known at compile time, so Python can use it to completely discard conditional blocks predicated on <span style="font-family: "Courier New",Courier,monospace;">__debug__</span>, just as it does with <span style="font-family: "Courier New",Courier,monospace;">assert<span style="font-family: inherit;"> </span></span>statements, when running with the <span style="font-family: "Courier New",Courier,monospace;">-O</span> flag. And in fact, this is exactly what Python does!<br />
<br />
The upshot is that you can write debug code that is stripped by Python's -O flag <i>without</i> abusing <span style="font-family: "Courier New",Courier,monospace;">assert</span>. This is easily demonstrated using Python's bytecode dissambler, <span style="font-family: "Courier New",Courier,monospace;">dis</span>.<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">from dis import dis</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
<span style="font-family: "Courier New",Courier,monospace;">def debug_func():</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> if __debug__:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> print "debugging"</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> return</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
<span style="font-family: "Courier New",Courier,monospace;">def noop_func():</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> return</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
<span style="font-family: "Courier New",Courier,monospace;">print "debug_func:" </span><br />
<span style="font-family: "Courier New",Courier,monospace;">dis(debug_func)</span><br />
<span style="font-family: "Courier New",Courier,monospace;">print</span><br />
<span style="font-family: "Courier New",Courier,monospace;">print "noop_func:" </span><br />
<span style="font-family: "Courier New",Courier,monospace;">dis(noop_func)</span><br />
<br />
Save this as <span style="font-family: "Courier New",Courier,monospace;">debugtest.py</span>, then execute it with <span style="font-family: "Courier New",Courier,monospace;">python -O debugtest.py</span>. You'll see that the disassembly of the two functions is identical aside from the line number offsets. It's just as if we never even wrote the <span style="font-family: "Courier New",Courier,monospace;">if</span> statement and its subordinate <span style="font-family: "Courier New",Courier,monospace;">print</span> statement! Literally zero performance impact to production code.<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">debug_func:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 4 0 LOAD_CONST 0 (None)<br /> 3 RETURN_VALUE</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
<span style="font-family: "Courier New",Courier,monospace;">noop_func:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 2 0 LOAD_CONST 0 (None)<br /> 3 RETURN_VALUE</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
What's more, when we run this script <i>without</i> the <span style="font-family: "Courier New",Courier,monospace;">-O</span> flag, Python optimizes away the test. That is, Python knows <span style="font-family: "Courier New",Courier,monospace;">__debug__</span> is true at compile time, and so it just compiles the code inside the <span style="font-family: "Courier New",Courier,monospace;">if</span> statement as if it <i>weren't</i> inside an <span style="font-family: "Courier New",Courier,monospace;">if</span> statement! Here's what the disassembly of <span style="font-family: "Courier New",Courier,monospace;">debug_func</span> looks like when <span style="font-family: "Courier New",Courier,monospace;">__debug__</span> is <span style="font-family: "Courier New",Courier,monospace;">True</span> (i.e., no <span style="font-family: "Courier New",Courier,monospace;">-O</span> flag is used):<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">debug_func: </span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 3 0 LOAD_CONST 1 ('debugging')<br /> 3 PRINT_ITEM<br /> 4 PRINT_NEWLINE<br /><br /> 4 5 LOAD_CONST 0 (None)<br /> 8 RETURN_VALUE </span><br />
<br />
By comparison, here's what it would look like if we were using some other conditional (say, a global variable called <span style="font-family: "Courier New",Courier,monospace;">DEBUG</span>). You'll see that this is much more complicated, and if you time it, you'll find that executing the test at runtime actually adds significant overhead.<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">debug_func:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 2 0 LOAD_GLOBAL 0 (DEBUG)<br /> 3 JUMP_IF_FALSE 9 (to 15)<br /> 6 POP_TOP<br /><br /> 3 7 LOAD_CONST 1 ('debugging')<br /> 10 PRINT_ITEM<br /> 11 PRINT_NEWLINE<br /> 12 JUMP_FORWARD 1 (to 16)<br /> >> 15 POP_TOP<br /> >> 16 LOAD_CONST 0 (None)<br /> 19 RETURN_VALUE</span><br />
<br />
So basically, Python will not only strip debugging code if it's conditionalized by testing <span style="font-family: "Courier New",Courier,monospace;">__debug__</span>, it will <i>also</i> slightly improve the performance of your debug code when running in debug mode compared to testing a runtime flag. And best of all, it does this magic using the same command line flag, <span style="font-family: "Courier New",Courier,monospace;">-O</span>, that strips assert statements! (For completeness, I should mention here that the <span style="font-family: "Courier New", Courier, monospace;">PYTHONOPTIMIZE</span> environment variable serves the same function as <span style="font-family: "Courier New", Courier, monospace;">-O</span>.)<br />
<br />
But wait, there's more! If you use an <span style="font-family: "Courier New",Courier,monospace;">else</span> clause with your <span style="font-family: "Courier New",Courier,monospace;">if __debug__</span> statement, Python is smart enough to strip whichever clause doesn't apply and "inline" the clause that does!<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">def get_run_mode():</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> if __debug__:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> return "debug"</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> else:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> return "production" </span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
<span style="font-family: "Courier New",Courier,monospace;">dis(get_run_mode) running without -O:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 3 0 LOAD_CONST 1 ('debug')<br /> 3 RETURN_VALUE</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
<span style="font-family: "Courier New",Courier,monospace;">dis(get_run_mode) running with -O:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 5 0 LOAD_CONST 1 ('production')<br /> 3 RETURN_VALUE</span><br />
<br />
Once again, for comparison, here's how the bytecode looks when the function is written to force runtime evaluation of the condition, by using a global variable <span style="font-family: "Courier New",Courier,monospace;">DEBUG</span> instead of _<span style="font-family: "Courier New",Courier,monospace;">_debug__</span>:<br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: inherit;"></span></span><span style="font-family: "Courier New",Courier,monospace;"><br /></span>
<span style="font-family: "Courier New",Courier,monospace;"> 2 0 LOAD_GLOBAL 0 (DEBUG)<br /> 3 JUMP_IF_FALSE 5 (to 11)<br /> 6 POP_TOP<br /><br /> 3 7 LOAD_CONST 1 ('debug')<br /> 10 RETURN_VALUE<br /> >> 11 POP_TOP<br /><br /> 5 12 LOAD_CONST 2 ('production')<br /> 15 RETURN_VALUE<br /> 16 LOAD_CONST 0 (None)<br /> 19 RETURN_VALUE</span><br />
<br />
So, is Python smart enough to optimize <span style="font-family: "Courier New",Courier,monospace;">if not __debug__</span> in the same way? Sadly, no:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">def not_debug_test():</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> if not __debug__:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> print "production"</span><br />
<br />
Bytecode:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">>>> dis(not_debug_test)<br /> 2 0 LOAD_GLOBAL 0 (__debug__)<br /> 3 JUMP_IF_TRUE 9 (to 15)<br /> 6 POP_TOP<br /><br /> 3 7 LOAD_CONST 1 ('production')<br /> 10 PRINT_ITEM<br /> 11 PRINT_NEWLINE<br /> 12 JUMP_FORWARD 1 (to 16)<br /> >> 15 POP_TOP<br /> >> 16 LOAD_CONST 0 (None)<br /> 19 RETURN_VALUE</span><br />
<br />
So if you want to write code that's run only in production, don't use <span style="font-family: "Courier New",Courier,monospace;">if not __debug__</span>. Write it like this instead:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"> if __debug__:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> pass</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> else:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> print "production" </span><br /><br />This is ugly, but arguably, it should be: you generally shouldn't write code that is only run in production, because it doesn't get tested.<br /><br />
What about conditional expressions, such as <span style="font-family: "Courier New",Courier,monospace;">x = "yes" if __debug__ else "no"</span>? Sadly, Python does not optimize these. Similarly, <span style="font-family: "Courier New",Courier,monospace;">__debug__ and x</span> and <span style="font-family: "Courier New",Courier,monospace;">__debug__ or x</span> are not optimized, though they could be.<br />
<br />
So what did we learn?<br />
<ol>
<li>Use <span style="font-family: "Courier New",Courier,monospace;">if __debug__</span> to write debug code (along with <span style="font-family: "Courier New",Courier,monospace;">else</span> if desired).</li>
<li>Don't make up your own flag for this, as it will prevent Python from being clever.</li>
<li>Don't use <span style="font-family: "Courier New",Courier,monospace;">if not __debug__</span> because this will also prevent Python from being clever.</li>
<li>Prefer <span style="font-family: "Courier New",Courier,monospace;">if</span> statements to using <span style="font-family: "Courier New",Courier,monospace;">__debug__</span> in logical expressions.</li>
<li>Use <span style="font-family: "Courier New",Courier,monospace;">assert</span> to assert invariants, not to perform stupid Python tricks like I presented last June.</li>
<li>Use the <span style="font-family: "Courier New",Courier,monospace;">-O</span> command line flag (or <span style="font-family: "Courier New", Courier, monospace;">PYTHONOPTIMIZE</span>) to tell Python when it's running in production. If you don't, you may be executing debugging code you don't want, with the potential performance degradation that implies.</li>
</ol>
Thanks to user Reddit user "brucifer" who posted <a href="http://www.reddit.com/r/Python/comments/1a5tc6/a_powerful_unused_feature_of_python_function/c8uzi6g" target="_blank">this informative comment</a>, and to user "Rainfly_X" who <a href="http://www.reddit.com/r/Python/comments/1a5tc6/a_powerful_unused_feature_of_python_function/c8uupp5" target="_blank">brought it to my attention</a>.<br />
<br />
By the way, in Python 3.x, <span style="font-family: "Courier New",Courier,monospace;">True</span> and <span style="font-family: "Courier New",Courier,monospace;">False</span> are also constants whose value is known at compile-time, and Python optimizes <span style="font-family: "Courier New",Courier,monospace;">if True</span> and <span style="font-family: "Courier New",Courier,monospace;">if False</span> similarly. In Python 2.x, the values of <span style="font-family: "Courier New",Courier,monospace;">True</span> and <span style="font-family: "Courier New",Courier,monospace;">False</span> can be changed at run time (seriously, try it if you don't believe me!), so this optimization isn't possible. <span style="font-family: "Courier New",Courier,monospace;">None</span> can't be changed in Python 2.x, but is only a true compile-time constant in Python 3.x, with the upshot that code under <span style="font-family: "Courier New",Courier,monospace;">if None</span> is also subject to being stripped out in Python 3.x but not in Python 2.x.Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com2tag:blogger.com,1999:blog-6054256360496337608.post-69578175794108977882012-12-09T21:23:00.003-08:002012-12-20T08:48:15.923-08:00Better Python APIsOz Katz has a good entry over at his blog, Eventual Consistency, about <a href="http://ozkatz.github.com/better-python-apis.html" target="_blank">making better APIs</a> for your Python libraries.Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com1tag:blogger.com,1999:blog-6054256360496337608.post-60407257514062877092012-12-05T11:21:00.000-08:002012-12-09T21:27:05.986-08:00PP #1: The always-true condition<i>Python Pitfalls are quirks of the Python programming language that
may trip up those new to the language or to programming. First in yet
another series.</i><br />
<br />
My experience with Python is that
my code usually does what I expect it to—in fact, more so than with any
other programming language I've used. But that doesn't mean it's
impossible to write code that doesn't do what you expect! Far from it. I
see code like this on Stack Overflow pretty much every day:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">while True: </span><br />
<span style="font-family: "Courier New",Courier,monospace;"> command = raw_input("command> ").lower().strip()</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> if command == "stop" or "exit":</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> break</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> elif command == "help":</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> print "quit, exit: exit the program"</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> print "help: display this help message"</span><span style="font-family: "Courier New",Courier,monospace;"> </span><br />
<span style="font-family: "Courier New",Courier,monospace;"> elif command:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> print "Unrecognized command."</span><br />
<br />
Can you guess the question? It's some variation of "No matter what command I enter, it always exits."<br />
<br />
And the reason is always the same: a Boolean expression using <span style="font-family: "Courier New",Courier,monospace;">or</span> that is always truthy. (See <a href="http://www.engyrus.com/2012/06/pf-1-truth-and-consequences.html" target="_blank">PF #1: Truth and Consequences</a>.) In this case, it's this line:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"> if command == "quit" or "exit":</span><br />
<br />
The programmer who wrote that line intended it to match either "quit" or "exit." Instead, it matches <i>any</i> command. The reason for this becomes obvious if we look at how Python evaluates the condition.<br />
<br />
As described in <a href="http://www.engyrus.com/2012/07/pf-2-and-andor-or.html" target="_blank">PF #2: And and/or or</a>, the value of a Boolean <span style="font-family: "Courier New",Courier,monospace;">or</span> operation is truthy if either operand is truthy. The operands of <span style="font-family: "Courier New",Courier,monospace;">or</span> here are:<br />
<ul>
<li><span style="font-family: "Courier New",Courier,monospace;">command == "quit"</span></li>
<li><span style="font-family: "Courier New",Courier,monospace;">"exit"</span></li>
</ul>
The latter operand, being a string with nonzero length, is truthy in Python, and therefore the result of the <span style="font-family: "Courier New",Courier,monospace;">or</span> is always truthy. Therefore, this test matches everything and the suite under the <span style="font-family: "Courier New",Courier,monospace;">if</span> is always executed!<br />
<br />
This
error is particularly pernicious because it reads exactly how you would
phrase it in English, and expresses the programmer's intent clearly. It's just that the
meaning of <span style="font-family: "Courier New",Courier,monospace;">or</span> is more specific in Python than in English.<br />
<br />
One way to write this test so that it works as expected is to explicitly tell Python to test <span style="font-family: "Courier New",Courier,monospace;">command</span> against both alternatives:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"> if command == "quit" or command == "exit":</span><br />
<br />
Of course, there's a shorter and clearer way to write this in Python:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"> if command in ("quit", "exit"):</span><br />
<br />
If
you will be testing for a lot of alternatives and performance is
important, use a <span style="font-family: "Courier New",Courier,monospace;">set</span> defined outside the loop. Testing for membership
in an existing set is a lot faster than testing for membership in a tuple
that's created new each time the test is executed.<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">exit_synonyms = set(["quit", "halt", "stop", </span><br />
<span style="font-family: "Courier New",Courier,monospace;"> "end", "whoa", "exit"])</span><br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">while True: </span><br />
<span style="font-family: "Courier New",Courier,monospace;"> command = raw_input("command> ").lower().strip()</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> if command in exit_synonyms:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> break</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> # and so on as above </span>Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com0tag:blogger.com,1999:blog-6054256360496337608.post-1981205195891408442012-12-04T09:30:00.002-08:002012-12-07T11:31:43.879-08:00PF #3: Non-short-circuiting Boolean operations<i>Third entry in the Python Foundations series, thoroughly exploring the basic building blocks of Python programs.</i><br />
<br />
Wow, it's been months, hasn't it? Our last <a href="http://www.engyrus.com/2012/07/pf-2-and-andor-or.html" target="_blank">Python Foundations entry</a> talked about how the Boolean operators <span style="font-family: "Courier New",Courier,monospace;">and</span> and <span style="font-family: "Courier New",Courier,monospace;">or</span> work in Python, including their <i>short-circuting</i> behavior. But what if you don't want short-circuiting? What if you want both operands of <span style="font-family: "Courier New",Courier,monospace;">and</span> or <span style="font-family: "Courier New",Courier,monospace;">or</span> to be fully evaluated even when the first operand's value is sufficient to determine the expression's truth value?<br />
<br />
Here, we can take advantage of the fact that Booleans are a special kind of integer in Python (see <a href="http://www.engyrus.com/2012/07/idktap-2-booleans-as-fancy-integers.html" target="_blank">IDKTAP #2: Booleans as fancy integers</a>), and <i>perform math on them.</i><br />
<br />
If you create a table of the results of adding the various combinations of 0 and 1, which are the integer values of <span style="font-family: "Courier New",Courier,monospace;">False</span> and <span style="font-family: "Courier New",Courier,monospace;">True</span> in Python:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">+ | 0 1</span><br />
<span style="font-family: "Courier New",Courier,monospace;">----------</span><br />
<span style="font-family: "Courier New",Courier,monospace;">0 | 0 1</span><span style="font-family: "Courier New",Courier,monospace;"> </span><br />
<span style="font-family: "Courier New",Courier,monospace;">1 | 1 2</span><br />
<br />
It bears a striking resemblance to the results of the Boolean <span style="font-family: "Courier New",Courier,monospace;">or</span> operator: the result is truthy (see <a href="http://www.engyrus.com/2012/06/pf-1-truth-and-consequences.html" target="_blank">PF #1: Truth and Consequences</a>) if either of the operands is truthy.<br />
<br />
Similarly, the multiplication operator is a dead ringer for Boolean <span style="font-family: "Courier New",Courier,monospace;">and</span>: <br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">* | 0 1</span><br />
<span style="font-family: "Courier New",Courier,monospace;">----------</span><br />
<span style="font-family: "Courier New",Courier,monospace;">0 | 0 0</span><span style="font-family: "Courier New",Courier,monospace;"> </span><br />
<span style="font-family: "Courier New",Courier,monospace;">1 | 0 1</span><br />
<br />
Zero times anything is zero, just as <span style="font-family: "Courier New",Courier,monospace;">False<span style="font-family: inherit;"> </span>and</span> anything is <span style="font-family: "Courier New",Courier,monospace;">False</span>.<br />
<br />
If
you have studied digital electronics, you may recognize this as Boolean
arithmetic: arithmetic using only the values 0 and 1, where <span style="font-family: "Courier New",Courier,monospace;">and</span> is in fact equivalent to multiplication and <span style="font-family: "Courier New",Courier,monospace;">or</span>
is equivalent to addition. The result of addition is "clamped" to 1
(that is, the highest result an addition can be is 1), and the only
valid operations are addition and multiplication. It may seem like a toy
arithmetic, but it's the foundation of everything a computer does.<br />
<br />
We can use this equivalence of logical and arithmetic operations to implement non-short-circuiting ("long-circuiting"?) <span style="font-family: "Courier New",Courier,monospace;">and</span> and <span style="font-family: "Courier New",Courier,monospace;">or</span>
in Python. To support truthy and falsy values, which may not actually
be integers, we convert the operands to proper Booleans first using the <span style="font-family: "Courier New",Courier,monospace;">bool()</span> constructor.<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">bool(x) + bool(y) + bool(z) # x or y or z</span><br />
<span style="font-family: "Courier New",Courier,monospace;">bool(x) * bool(y) * bool(z) # x and y and z</span><br />
<br />
Here, <span style="font-family: "Courier New",Courier,monospace;">x</span>, <span style="font-family: "Courier New",Courier,monospace;">y</span>, and <span style="font-family: "Courier New",Courier,monospace;">z</span>
are always fully evaluated. If one of them is, say, a function call,
the function is always called. In the equivalent expression using
Boolean operators, remember, the expression will short-circuit as soon
as it can, and may not evaluate all arguments. We explored how to
exploit this behavior for fun and profit in <a href="http://www.engyrus.com/2012/07/pf-2-and-andor-or.html" target="_blank">PF #2</a>.<br />
<br />
Conveniently,
multiplication has precedence over (is performed before) addition, just
as <span style="font-family: "Courier New",Courier,monospace;">and</span> has precedence over <span style="font-family: "Courier New",Courier,monospace;">or</span>, so an expression like the following
works exactly as you would expect:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">bool(a) * bool(b) + bool(x) * bool(y) # a and b or x and y</span><br />
<br />
In fact, this is an easy way to remember which Boolean operator has precedence: <i>because</i> <span style="font-family: "Courier New",Courier,monospace;">and</span> is equivalent to multiplication, it has precedence over <span style="font-family: "Courier New",Courier,monospace;">or</span>, which is equivalent to addition. This is a rule I had trouble remembering when I started programming.<br />
<br />
So
far, what we've discussed isn't really specific to Python; you can do the same
non-short-circuiting Boolean math in virtually any language with only
minor syntax changes. We can, however, use Python's <span style="font-family: "Courier New",Courier,monospace;">any()</span> and <span style="font-family: "Courier New",Courier,monospace;">all()</span> functions to help make our non-short-circuiting Boolean operators a little more readable. Both functions operate on a sequence.<br />
<ul>
<li><span style="font-family: "Courier New",Courier,monospace;">any()</span> - Returns <span style="font-family: "Courier New",Courier,monospace;">True</span> if any element is truthy (equivalent to Boolean <span style="font-family: "Courier New",Courier,monospace;">or</span>)</li>
<li><span style="font-family: "Courier New",Courier,monospace;">all()</span> - Returns <span style="font-family: "Courier New",Courier,monospace;">True</span> if all elemens are truthy (equivalent to Boolean <span style="font-family: "Courier New",Courier,monospace;">and</span>)</li>
</ul>
Technically, <span style="font-family: "Courier New",Courier,monospace;">any()</span>and <span style="font-family: "Courier New",Courier,monospace;">all()</span>
do in fact short-circuit: they will stop inspecting elements in the sequence as
soon as they see a value that definitively determines the result. That
is, <span style="font-family: "Courier New",Courier,monospace;">all()</span> returns <span style="font-family: "Courier New",Courier,monospace;">False</span>
when it sees the first falsy element, because a single such element is
enough to know that not all elements are truthy. And <span style="font-family: "Courier New",Courier,monospace;">any()</span> returns <span style="font-family: "Courier New",Courier,monospace;">True</span> when it sees the first truthy element, because that's enough to know that there is at least one such.<br />
<br />
However,
the short-circuiting behavior is apparent only with generators, which
"lazily" calculates a sequence one element at a time. (There will surely
be a Python Foundations entry on generators in the future!) If you pass
a sequence (i.e., a list or a tuple) to <span style="font-family: "Courier New",Courier,monospace;">any()</span> or <span style="font-family: "Courier New",Courier,monospace;">all()</span>, all the elements of the sequence will be fully evaluated when the sequence is constructed, before <span style="font-family: "Courier New",Courier,monospace;">any()</span> or <span style="font-family: "Courier New",Courier,monospace;">all()</span> is even involved. The fact that <span style="font-family: "Courier New",Courier,monospace;">any()</span> and <span style="font-family: "Courier New",Courier,monospace;">all()</span> short-circuit is then merely a performance optimization. Useful, in other words, but not exploitable for side effects as with <span style="font-family: "Courier New",Courier,monospace;">and</span> and <span style="font-family: "Courier New",Courier,monospace;">or</span>.<br />
<br />
And so we can use <span style="font-family: "Courier New",Courier,monospace;">any()</span> and <span style="font-family: "Courier New",Courier,monospace;">all()</span> as non-short-circuiting <span style="font-family: "Courier New",Courier,monospace;">or</span> and <span style="font-family: "Courier New",Courier,monospace;">and</span>, respectively. <span style="font-family: "Courier New",Courier,monospace;">x</span>, <span style="font-family: "Courier New",Courier,monospace;">y</span>, and <span style="font-family: "Courier New",Courier,monospace;">z</span> below may be expressions of arbitrary complexity, and will be evaluated fully.<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">any([x, y]) # x or y</span><br />
<span style="font-family: "Courier New",Courier,monospace;">all([x, y]) # x and y</span><br />
<span style="font-family: "Courier New",Courier,monospace;">any([x, y, z]) # x or y or z (any number of arguments)</span><br />
<span style="font-family: "Courier New",Courier,monospace;">all((x, y, z)) # you may use a tuple instead of a list</span><br />
<br />
<br />
As
for the last example, I personally prefer using the square brackets and
passing a list since it stands out more and makes it clearer what is
happening, but constructing a tuple is faster, a fact which may be
useful in some circumstances.<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">any()</span> and <span style="font-family: "Courier New",Courier,monospace;">all()</span> can be nested to implement compound non-short-circuiting Boolean operations:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">any([all([a, b]), all([x, y]]) # a and b or x and y</span><br />
<br />
However,
this gets difficult to read pretty quickly (unless, perhaps, you have
experience with Lisp, where all operations are prefix).. Fortunately, <span style="font-family: "Courier New",Courier,monospace;">any()</span> and <span style="font-family: "Courier New",Courier,monospace;">all()</span> always return <span style="font-family: "Courier New",Courier,monospace;">True</span> or <span style="font-family: "Courier New",Courier,monospace;">False</span>
(not the deciding element from the sequence, which may be merely truthy
or falsy), so you can easily combine their results with <span style="font-family: "Courier New",Courier,monospace;">+</span> and <span style="font-family: "Courier New",Courier,monospace;">*</span>.<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">all([a, b]) + all([x, y]) # a and b or x and y, as above</span><br />
<br />
We're almost finished here; this has become rather more in-depth than I intended! But while were talking about <span style="font-family: "Courier New",Courier,monospace;">any()</span> and <span style="font-family: "Courier New",Courier,monospace;">all()</span>,
I should mention that it is something of a shame that neither returns the value that made the decision (i.e., the first truthy
value for <span style="font-family: "Courier New",Courier,monospace;">any()</span> or the first falsy value for <span style="font-family: "Courier New",Courier,monospace;">all()</span>).
This keeps them from being used to actually <i>find</i> the first truthy or falsy value in a sequence, which is especially a pity when you're using them with a generator because that value, having been <i>consumed </i>within <span style="font-family: "Courier New",Courier,monospace;">any()</span>/<span style="font-family: "Courier New",Courier,monospace;">all()</span>, is forever lost.<br />
<br />
You can write your own versions of these functions that do return the deciding value, but because they are
implemented in Python rather than in C, they will be slower than the
built-ins. Still, here are such implementations.<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">def all(iterable):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> for item in iterable:</span><span style="font-family: "Courier New",Courier,monospace;"> </span><br />
<span style="font-family: "Courier New",Courier,monospace;"> if not item: return item</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> return True</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
<span style="font-family: "Courier New",Courier,monospace;">def any(iterable):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> for item in iterable:</span><span style="font-family: "Courier New",Courier,monospace;"> </span><br />
<span style="font-family: "Courier New",Courier,monospace;"> if item: return item</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> return False</span><br />
<br />Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com0tag:blogger.com,1999:blog-6054256360496337608.post-33378760989260507992012-07-11T17:19:00.001-07:002012-07-12T10:49:21.916-07:00IDKTAP #3: BackticksDid you know that quoting an expression using backticks is an alias for <span style="font-family: "Courier New",Courier,monospace;">repr()</span> in Python 2.x? That is, it prints the "representation" of the result of the expression, which is generally what you'd have to paste into your Python source file to produce that same object.<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">print `"Think, it ain't illegal yet!"`</span><br />
<br />
They took this out in Python 3.Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com2tag:blogger.com,1999:blog-6054256360496337608.post-48695312817587317942012-07-05T15:53:00.000-07:002012-07-05T15:55:54.060-07:00IDKTAP #2: Booleans as fancy integers<i>I Didn't Know That About Python uncovers surprising tidbits about our favorite programming language. </i><br />
<br />
In Python, a Boolean (type <span style="font-family: "Courier New",Courier,monospace;">bool</span>) is a subtype of integers. <span style="font-family: "Courier New",Courier,monospace;">True</span> is equal to 1 and <span style="font-family: "Courier New",Courier,monospace;">False</span> is equal to 0.<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">True == 1 # True</span><br />
<span style="font-family: "Courier New",Courier,monospace;">False == 0 # True</span><br />
<br />
The special methods called <span style="font-family: "Courier New",Courier,monospace;">__str__</span> and <span style="font-family: "Courier New",Courier,monospace;">__repr__</span> define how an object is converted to a string and how it is represented in an interactive context, respectively. So <span style="font-family: "Courier New",Courier,monospace;">bool</span> is basically implemented like this:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">class bool(int):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> def __str__(self):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> return "True" if self else "False"</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> __repr__ = __str__</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span><br />
<span style="font-family: "Courier New",Courier,monospace;">True, False = bool(1), bool(0)</span><br />
<br />
(There are some other details I'm glossing over, such as the fact that <span style="font-family: "Courier New",Courier,monospace;">True</span> and <span style="font-family: "Courier New",Courier,monospace;">False</span> are singletons and only ever have one instance. That is, <span style="font-family: "Courier New",Courier,monospace;">bool(1)</span> is always the same object. The example above does not have this behavior. For a fun exercise, try adding it.)<br />
<br />
The surprising thing is that in Python 2, <span style="font-family: "Courier New",Courier,monospace;">True</span> and <span style="font-family: "Courier New",Courier,monospace;">False</span> are simply built-in identifiers assigned to two specific <span style="font-family: "Courier New",Courier,monospace;">bool</span> singletons. This means that they can be reassigned:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">True = 3</span><br />
<br />
This will very likely cause quite odd behavior in your programs, which is why Python 3 reserves <span style="font-family: "Courier New",Courier,monospace;">True</span> and <span style="font-family: "Courier New",Courier,monospace;">False</span> as actual language keywords and doesn't let you reassign them. Still, <span style="font-family: "Courier New",Courier,monospace;">issubclass(bool, int)</span> remains <span style="font-family: "Courier New",Courier,monospace;">True</span>.Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com1tag:blogger.com,1999:blog-6054256360496337608.post-41681928143289729272012-07-01T09:19:00.004-07:002012-09-18T10:04:52.281-07:00PF #2: And and/or or<i>Second in the Python Foundations series.</i><br />
<br />
In the previous installment of Python Foundations, I described the informal nature of truth and falsity in Python (dubbed "truthy" and "falsy"). Now let's explore how the Boolean operators <span style="font-family: "Courier New",Courier,monospace;">and</span> and <span style="font-family: "Courier New",Courier,monospace;">or</span> interact with such values.<br />
<br />
In many languages, you'd expect the result of a Boolean operation (an operation between two truth values) to be <span style="font-family: "Courier New",Courier,monospace;">True</span> or <span style="font-family: "Courier New",Courier,monospace;">False</span>. But since Python considers a wide range of values <span style="font-family: "Courier New",Courier,monospace;">True</span> and <span style="font-family: "Courier New",Courier,monospace;">False</span> in a Boolean context, it is useful to return one of the operands. That is, when you combine two values using <span style="font-family: "Courier New",Courier,monospace;">and</span> or <span style="font-family: "Courier New",Courier,monospace;">or</span>, you get one of the values you put in.<br />
<br />
In Python, <span style="font-family: "Courier New",Courier,monospace;">and</span> and <span style="font-family: "Courier New",Courier,monospace;">or</span> are <i>short-circuiting</i>. They always evaluate their first operand, and if that result is sufficient to decide the truth value of the expression, they stop and <i>don't evaluate their second operand.</i> Say what?<br />
<br />
OK, have a look at the truth table for <span style="font-family: "Courier New",Courier,monospace;">and</span>:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">AND | True False</span><br />
<span style="font-family: "Courier New",Courier,monospace;">-----------------------<br />True | True False</span><br />
<span style="font-family: "Courier New",Courier,monospace;">False | False False</span><br />
<br />
As you can see, <span style="font-family: "Courier New",Courier,monospace;">False</span> <span style="font-family: "Courier New",Courier,monospace;">and</span> anything is always <span style="font-family: "Courier New",Courier,monospace;">False</span>. Therefore, when the first operand of <span style="font-family: "Courier New",Courier,monospace;">and</span> is falsy, Python need not evaluate the second operand, and in fact does not. This not only saves time, it can be exploited for useful side effects (more on that later).<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">OR | True False</span><br />
<span style="font-family: "Courier New",Courier,monospace;">-----------------------<br />True | True True</span><br />
<span style="font-family: "Courier New",Courier,monospace;">False | True False</span><br />
<br />
This truth table for <span style="font-family: "Courier New",Courier,monospace;">or</span> similarly reveals that when the first operand is <span style="font-family: "Courier New",Courier,monospace;">True</span>, the result is always <span style="font-family: "Courier New",Courier,monospace;">True</span>, so Python doesn't need to evaluate the second operand of <span style="font-family: "Courier New",Courier,monospace;">or</span> when the first operand is truthy. And once again, since it doesn't need to, it doesn't.<br />
<br />
What does it mean to not evaluate the second operand of <span style="font-family: "Courier New",Courier,monospace;">and</span> or <span style="font-family: "Courier New",Courier,monospace;">or</span>? Among other things it means that if the second operand is a function call, that second function is never called:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">v = a() or b()</span><br />
<br />
If <span style="font-family: "Courier New",Courier,monospace;">a()</span> returns something truthy, <span style="font-family: "Courier New",Courier,monospace;">b()</span> is never even called. But what is the value of <span style="font-family: "Courier New",Courier,monospace;">v</span>? Python assigns <span style="font-family: "Courier New",Courier,monospace;">v</span> the return value of the operand that decided the result: <span style="font-family: "Courier New",Courier,monospace;">a()</span> if <span style="font-family: "Courier New",Courier,monospace;">a</span>'s return value is truthy, or <span style="font-family: "Courier New",Courier,monospace;">b()</span> if <span style="font-family: "Courier New",Courier,monospace;">a</span>'s return value is falsy. It works similarly with <span style="font-family: "Courier New",Courier,monospace;">and</span>, except the result is <span style="font-family: "Courier New",Courier,monospace;">a</span>'s return value if it is falsy and <span style="font-family: "Courier New",Courier,monospace;">b</span>'s otherwise. In short, the actual operand values are used in place of the constants <span style="font-family: "Courier New",Courier,monospace;">True</span> and <span style="font-family: "Courier New",Courier,monospace;">False</span>.<br />
<br />
Short-circuiting lets you use <span style="font-family: "Courier New",Courier,monospace;">and</span> and <span style="font-family: "Courier New",Courier,monospace;">or</span> as substitutes for <span style="font-family: "Courier New",Courier,monospace;">if</span> statements in certain circumstances. It's very easy to write unreadable code using short-circuiting <span style="font-family: "Courier New",Courier,monospace;">and</span> and <span style="font-family: "Courier New",Courier,monospace;">or</span>; there was an idiom that was commonly used in an attempt to make up for the fact that Python didn't have a proper ternary conditional operator. Then Python added a proper ternary conditional operator (<span style="font-family: "Courier New",Courier,monospace;">v = a if b else c</span>) and everybody forgot about the hackish workaround. But simpler uses of short-circuiting are pretty readable and useful.<br />
<br />
For example, easily provide a default value for blank inputs:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">name = raw_input("What is your name? ") or "Jude"</span><br />
<span style="font-family: "Courier New",Courier,monospace;">print "Hey,", name, "don't make it bad"</span><br />
<br />
Or check to make sure something is callable before calling it:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">callable(func) and func()</span><br />
<br />
I find those generally more readable than the alternatives using if statements:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">name = raw_input("What is your name? ")</span><br />
<span style="font-family: "Courier New",Courier,monospace;">if not name:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> name = "Jude"</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
<span style="font-family: "Courier New",Courier,monospace;">if callable(func):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> func()</span><br />
<br />
Short-circuiting is, by the way, the reason Python doesn't let you override <span style="font-family: "Courier New",Courier,monospace;">and</span> and <span style="font-family: "Courier New",Courier,monospace;">or</span> using special methods on your own objects the way you can with arithmetic operators. Both operands would be evaluated before the operation is performed, so short-circuiting simply isn't possible. (There is in fact a proposal to change that, but it hasn't been implemented yet.)Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com0tag:blogger.com,1999:blog-6054256360496337608.post-39225864088670095682012-06-26T16:04:00.001-07:002012-06-28T10:06:48.064-07:00Recipe #1: An indexable file class<i>Python Recipes are simple bits of my code you can use freely in your own programs. First in a series. Yes, I'm gonna have a lot of different series of posts on this blog.</i> <br />
<br />
Here's a file-like class that allows access to lines in the file using Python indexing or slicing notation without reading the whole file into memory. It's sort of a list/file hybrid since it does have methods for incrementally reading from the file, too.<br />
<br />
<span style="font-family: "Courier New",Courier,monospace; font-size: small;">class linefile(object):<br /> <br /> def __init__(self, path):<br /> self.file = open(path)<br /> self.offsets = []<br /><br /> def __enter__(self):<br /> return self<br /><br /> def __exit__(self, *e):<br /> self.file.close()<br /><br /> def readline(self):<br /> self.offsets.append(int(self.file.tell()))<br /> text = self.file.readline()<br /> if not text:<br /> self.offsets.pop()<br /> return text<br /><br /> def readlines(self):<br /> for text in self:<br /> pass</span><br />
<span style="font-family: "Courier New",Courier,monospace; font-size: small;"> return self<br /><br /> def next(self):<br /> return self.readline()<br /><br /> def __iter__(self):<br /> text = self.readline()<br /> while text:<br /> yield text<br /> text = self.readline()<br /><br /> def __getitem__(self, index):<br /> offset = self.offsets[index]<br /> tell = self.file.tell()<br /> if type(index) is slice:</span><br />
<span style="font-family: "Courier New",Courier,monospace; font-size: small;"> if slice.s<span style="font-size: small;">tep =<span style="font-size: small;">=<span style="font-size: small;"> 1: # step is 1, <span style="font-size: small;">this is faste<span style="font-size: small;">st</span></span></span></span></span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"> self.file.seek(offset[0])</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> text = [self.file.readline() for line in offset]</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: small;"> else:</span></span><br />
<span style="font-family: "Courier New",Courier,monospace; font-size: small;"> text = [] </span><br />
<span style="font-family: "Courier New",Courier,monospace; font-size: small;"> <span style="font-size: small;">for o in offset:</span></span><br />
<span style="font-family: "Courier New",Courier,monospace; font-size: small;"> <span style="font-size: small;">self.file.seek(o)</span></span><br />
<span style="font-family: "Courier New",Courier,monospace; font-size: small;"><span style="font-size: small;"> text.append(self.fil<span style="font-size: small;">e.readline())</span> </span><br /> else:<br /> self.file.seek(offset)<br /> text = self.file.readline()<br /> self.file.seek(tell)<br /> return text<br /><br /> def __len__(self):<br /> return len(self.offsets)</span><br />
<br />
Unlike a regular file, a <span style="font-family: "Courier New",Courier,monospace;">linefile</span> is read-only and text-only. Internally, the instance stores the offsets of each line that has been read. The lines themselves are retrieved from the file on demand; the instance does not store any lines. Positive offsets index from the beginning of the file and negative offsets index from the last line read from the file, which may not be the end of the file. (Index -<span style="font-family: "Courier New",Courier,monospace;">1</span>, then, is the line before the current one.) You can use the <span style="font-family: "Courier New",Courier,monospace;">readlines()</span> method to read all the lines and thereby note the offset of each line of the file; this will allow the entire file to be accessed by index or slice as though it were a list. The <span style="font-family: "Courier New",Courier,monospace;">linefile</span> object is iterable and is also a context manager (i.e, it supports the <span style="font-family: "Courier New",Courier,monospace;">with</span> statement).Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com0tag:blogger.com,1999:blog-6054256360496337608.post-60838887029024300482012-06-24T22:23:00.002-07:002012-06-24T22:24:55.992-07:00The world's stupidest Mac backup softwareSo it appears that I'm running the world's stupidest backup software on my Mac.<br />
<br />
Last night, my "media" hard disk (with all my photos and music) failed. No problem, I have a backup. I look on the backup drive and boom, <i>there's no backup.</i><br />
<br />
Apparently this software was trying to keep the backup in sync with the original disk when I deleted files. The original disk was gone, so it made the backup match... by deleting it.<br />
<br />
Yeah, that was <i>real</i> helpful. Thanks, NTI Shadow.<br />
<br />
All that stuff can probably <i>(probably)</i> be recovered, since nothing else has been written to the backup drive. And I'm pretty sure the original disk can also be recovered, for a price. Still, what a pain.Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com0tag:blogger.com,1999:blog-6054256360496337608.post-61133137725098694272012-06-22T11:21:00.001-07:002013-11-08T20:38:42.429-08:00PF #1: Truth and Consequences<i>Intended for those new to the language but not to programming, "Python Foundations" surveys the parts of Python that you need to
know about to take full advantage of Python's power. First in a series.</i><br />
<br />
Many programming languages have somewhat loose concepts of truth and falsity. Objects can have a truth value even if they're not Booleans. In C, truth is canonically represented as <span style="font-family: "Courier New",Courier,monospace;">-1</span>, but any non-zero value is considered true in a Boolean context such as an <span style="font-family: "Courier New",Courier,monospace;">if</span> statement.<br />
<br />
Python takes this a step further, considering empty containers (including strings) to be false. The constant <span style="font-family: "Courier New",Courier,monospace;">None </span>is also considered false. Other objects are generally considered true, although this can be overridden (we'll discuss how in a moment). This property is useful for making code like this more readable:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">name = raw_input("What is your name? ")</span><br />
<span style="font-family: "Courier New",Courier,monospace;">while not name: # instead of while name == ""</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> name = raw_input("Seriously, what's your name? ")</span><br />
<br />
Since truth values are a little flexible, Python programmers have adopted the terms <i>truthy</i> and <i>falsy</i> (or <i>falsey</i>) to refer to an object's implicit truth value when used in a Boolean context. (I hasten to add that I don't believe these terms were <i>coined</i> in the Python community.)<br />
<br />
In other words, the list <span style="font-family: "Courier New",Courier,monospace;">[1, 2, 3]</span> is not literally equal to the constant <span style="font-family: "Courier New",Courier,monospace;">True</span>, but it is <i>truthy</i> because if you tested it with an <span style="font-family: "Courier New",Courier,monospace;">if</span> statement, that <span style="font-family: "Courier New",Courier,monospace;">if</span> statement's body would be executed.<br />
<br />
Instances of classes are generally truthy unless they are derived from a class that has some other built-in behavior (for example, a list, which, remember, is truthy when it contains any items). Functions, classes, iterators/generators, and modules are also truthy.<br />
<br />
You can override the implicit truth value of your own classes by defining either a <span style="font-family: "Courier New",Courier,monospace;">__len__()</span> or <span style="font-family: "Courier New",Courier,monospace;">__nonzero__()*</span> special method. If your class has a <span style="font-family: "Courier New",Courier,monospace;">__len__()</span> method, it is probably a container, and Python will treat its instances like one: false when its length is zero and true when its length is nonzero. The <span style="font-family: "Courier New",Courier,monospace;">__nonzero__()</span> method is more explicit and can indicate the instance's truth value even for non-container classes. If a class has both of these methods, <span style="font-family: "Courier New",Courier,monospace;">__nonzero__()</span> takes precedence.<br />
<br />
Here is a list subclass that is always truthy, even when empty:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">class truthylist(list):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> def __nonzero__(self):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> return True # always</span><br />
<br />
When would you want to use such a list? Well, consider a situation in which you are reading records from a database or elements from an XML file and will return a list of them. If an error occurs, you have two choices: raise an exception or return an error code. In some scenarios, it's even convenient to just return an empty list on error, since then you can use the same code path to iterate over it whether there was an error or not. But then you don't know why you got the empty list: was it because there was an error, or because there was no data of the type you requested? The truthy list gives us a solution.<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">def getrecords(key):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> try:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> result = ... # get the records here</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> else:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> return result if result else truthylist()</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> except Exception:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> return []</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> </span><br />
Now, when we call this function, we can just check to see if the result is truthy. If it is, we successfully retrieved the records (even if there are none). At the same time, we retain the ability to iterate over the records without regard for what happened, if that's what we want to do.<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">records = getrecords("DNA")</span><br />
<span style="font-family: "Courier New",Courier,monospace;">for record in records: print record</span><br />
<span style="font-family: "Courier New",Courier,monospace;">if records = []: print "No records found",</span><br />
<span style="font-family: "Courier New",Courier,monospace;">if not records: print "due to error",</span><br />
<span style="font-family: "Courier New",Courier,monospace;">print</span><br />
<br />
Admittedly, this verges on a Stupid Python Trick. The "empty container is falsy" convention is so engrained, other Python programmers will find <span style="font-family: "Courier New",Courier,monospace;">truthylist</span> more than a little odd.<br />
<br />
In the next installment of Python Foundations, we'll look at Python's logical operators and how implicit truth values interact with them.<br />
<br />
<span style="font-size: x-small;">*In Python 3, the <span style="font-family: "Courier New",Courier,monospace;">__nonzero__()</span> special method was renamed <span style="font-family: "Courier New",Courier,monospace;">__bool__()</span> to better match the other type-coercion methods such as <span style="font-family: "Courier New",Courier,monospace;">__str__()</span> and <span style="font-family: "Courier New",Courier,monospace;">__int__()</span>.</span>Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com0tag:blogger.com,1999:blog-6054256360496337608.post-38714954054594462302012-06-21T11:13:00.002-07:002012-06-21T11:14:05.482-07:00Tweetery @EngyrusYou can find me on Twitter <a href="https://twitter.com/#!/Engyrus" target="_blank">@Engyrus</a>. I'll post there each time I post something here.Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com0tag:blogger.com,1999:blog-6054256360496337608.post-53636028838837144312012-06-21T10:43:00.001-07:002012-06-22T10:01:00.380-07:00SPT #1: Automatically stripping debug code<i>"Stupid Python Tricks" explores ways to abuse Python features for fun and profit. This is the first in a series. Stupid Python Tricks are generally not best practices and may well be worst practices. Read at your own risk.</i><br />
<br />
The standard Python interpreter ("CPython") has a command line option <span style="font-family: "Courier New",Courier,monospace;">-O</span> that triggers "optimization." Currently, the only real optimization performed is to ignore <span style="font-family: "Courier New",Courier,monospace;">assert</span> statements. And they're not simply ignored at runtime; they are never even compiled into the byte code executed by the Python virtual machine.<br />
<br />
The value of this optimization is that you can sprinkle <span style="font-family: "Courier New",Courier,monospace;">assert</span>s liberally throughout your code to make sure it fails fast when something goes wrong, making it easier to debug. Yet, because all those statements are stripped out when Python is run in optimized mode, there's no performance penalty when the code is put into production.<br />
<br />
Wouldn't it be great if you could strip <i>all </i>your debug code just as easily? Many of us write functions like this to let us easily turn off our debug messages:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">def debug_print(*args):</span><span style="font-family: "Courier New",Courier,monospace;"> </span><br />
<span style="font-family: "Courier New",Courier,monospace;"> if DEBUG:</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> for arg in args: print arg,</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> print</span><br />
<br />
This can be optimized a bit to minimize overhead of the debug statements by checking the <span style="font-family: "Courier New",Courier,monospace;">DEBUG</span> flag only once and defining a do-nothing function when the flag isn't set:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">def debug_print(*args):</span><span style="font-family: "Courier New",Courier,monospace;"> </span><br />
<span style="font-family: "Courier New",Courier,monospace;"> for arg in args: print arg,</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> print</span><br />
<span style="font-family: "Courier New",Courier,monospace;">if not DEBUG: debug_print = lambda *args: None</span><br />
<br />
But there are still all those function calls to the dummy function being executed when running in non-debug mode. Plus, of course, you <i>still</i> need to define the <span style="font-family: "Courier New",Courier,monospace;">DEBUG</span> variable. So running in production requires both that you change that variable <i>and </i>put <span style="font-family: "Courier New",Courier,monospace;">-O</span> on the command line, doubling your chances of getting it wrong.<br />
<br />
How can we abuse Python's optimization to actually strip out the calls to our <span style="font-family: "Courier New",Courier,monospace;">debug_print</span> function? Simple: by writing it as an assertion. To avoid raising an <span style="font-family: "Courier New",Courier,monospace;">AssertionError</span>, of course, <span style="font-family: "Courier New",Courier,monospace;">debug_print</span> must always return <span style="font-family: "Courier New",Courier,monospace;">True</span>.<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">def debug_print(*args):</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> for arg in args: print arg,</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> print</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> return True</span><br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">assert debug_print("Checkpoint 1") </span><br />
<br />
Now we just need to run our script with <span style="font-family: "Courier New",Courier,monospace;">-O</span> and all those <span style="font-family: "Courier New",Courier,monospace;">debug_print</span> calls will be stripped automatically like we never even wrote them.<br />
<br />
If you're using Python 3 (or Python 2.6 or 2.7 with <span style="font-family: "Courier New",Courier,monospace;">from __future__ import print_function</span>), <span style="font-family: "Courier New",Courier,monospace;">print</span> is already a function. Seems like a waste to define a new <span style="font-family: "Courier New",Courier,monospace;">debug_print </span>in that case. But we need the result to be <span style="font-family: "Courier New",Courier,monospace;">True</span> and <span style="font-family: "Courier New",Courier,monospace;">print()</span> returns <span style="font-family: "Courier New",Courier,monospace;">None</span>, which evaluates as <span style="font-family: "Courier New",Courier,monospace;">False</span> in a Boolean context. Well, you can just write one of the following, any of which is guaranteed to be <span style="font-family: "Courier New",Courier,monospace;">True</span> (the first only for functions that return <span style="font-family: "Courier New",Courier,monospace;">None</span> or another falsey value, the other two always) and prevent <span style="font-family: "Courier New",Courier,monospace;">assert</span> from sounding an alarm.<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">assert not print("Checkpoint 1")</span><br />
<span style="font-family: "Courier New",Courier,monospace;">assert print("Checkpoint 1") or True</span><br />
<span style="font-family: "Courier New",Courier,monospace;">assert [print("Checkpoint 1")]</span><br />
<br />
Of these three, the last is what elevates this trick to the height of stupidity. Exploiting the fact that Python considers any non-empty container <span style="font-family: "Courier New",Courier,monospace;">True</span>, we simply make a list containing the return value from the function we called. The resulting code looks more like an unfamiliar bit of Python syntax than a dirty hack, but a dirty hack it is.<br />
<br />
By the way, this Stupid Python Trick obviously also works for calls to loggers or any other function you want to call in debug mode. <br />
<br />
<b>Why this is a bad idea: </b>It's very specific to current CPython behavior, which could change in the future, and may not have the desired effects with other Python implementations like IronPython and Jython. (Although it probably wouldn't hurt anything except possibly performance.) Furthermore, it's not really asserting anything about the program (the truth value is guaranteed to be <span style="font-family: "Courier New",Courier,monospace;">True</span> after all), but rather using the <span style="font-family: "Courier New",Courier,monospace;">assert</span> statement for its secondary effects, damaging Python's generally excellent readability.Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com1tag:blogger.com,1999:blog-6054256360496337608.post-34329902701312692352012-06-21T10:09:00.001-07:002012-06-21T11:50:34.938-07:00IDKTAP #1: Omitting "print" in the Python shell<i>"I Didn't Know That About Python" covers surprising little things I've learned about Python. Nothing earthshattering. First in a series. </i><br />
<br />
Most Python hackers have spent a lot of time exploring in the Python interactive shell, and therefore know that Python obligingly prints the results of expressions for you when they return a value:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">>>> 2+2</span><br />
<span style="font-family: "Courier New",Courier,monospace;">4</span><br />
<br />
You might be forgiven for assuming Python is just printing the result of the <i>last</i> expression it evaluated. But in fact, it's printing the result of <i>any and all</i> expressions that you don't do anything else with.<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">>>> 2+2; 3+3</span><br />
<span style="font-family: "Courier New",Courier,monospace;">4</span><br />
<span style="font-family: "Courier New",Courier,monospace;">6</span><br />
<span style="font-family: "Courier New",Courier,monospace;">>>> for x in xrange(5): x</span><br />
<span style="font-family: "Courier New",Courier,monospace;">... </span><br />
<span style="font-family: "Courier New",Courier,monospace;">0</span><br />
<span style="font-family: "Courier New",Courier,monospace;">1</span><br />
<span style="font-family: "Courier New",Courier,monospace;">2</span><br />
<span style="font-family: "Courier New",Courier,monospace;">3</span><br />
<span style="font-family: "Courier New",Courier,monospace;">4</span><br />
<br />
This behavior, though subtly different from what you might expect, lets you omit <span style="font-family: "Courier New",Courier,monospace;">print</span> much of the time in Python interactive mode, saving you precious <i>fractions of a second</i> each time. Because life is too short to spend it typing <span style="font-family: "Courier New",Courier,monospace;">print</span>!<br />
<br />
Thanks to Joel Cornett for pointing this out in a comment on <a href="http://stackoverflow.com/a/10957979/416467" target="_blank">a StackOverflow answer</a>.Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com0tag:blogger.com,1999:blog-6054256360496337608.post-35287611847244975812012-06-20T14:24:00.000-07:002012-06-21T11:15:11.253-07:00Welcome to EngyrusEngyrus is my one-man consulting sideline specializing in the Python programming language. I created this blog to share Python tips and tricks and information about the Python projects I'm working on, among other things. There'll probably be some Web stuff and some utilities made with AutoHotKey too.<br />
<br />
I'm Jerry Kindall, technical writer by trade. At my day job, I use Python to build and validate our documentation. Python has put the fun back in programming for me. Coding in Python reminds me a lot of my Apple II hacking days, but with longer variable names and fewer <span style="font-family: "Courier New",Courier,monospace;">GOTO</span>s.<br />
<br />
About the name: "Engyrus" is a disused scientific name for the genus Python (you know, snakes) dating back to the 1830s. As a collector of words, I really found this one lovely, so I appropriated it. (Much to my pleasure, the domain was available, too!)Jerry Kindallhttp://www.blogger.com/profile/15440244498042763932noreply@blogger.com0