Readability: Dictionaries are not data types

Yes: a dictionary is a data type. No: a dictionary is not a way to implement abstract data types; doing so is lazy programming and is asking for trouble later on. What do I mean by this? In Python and other similar dynamic languages, dictionaries are a mapping of keys to values that have no typing restrictions: the dictionary is heterogeneous, and a single dictionary can contain elements of different types both as its keys and its values. To make things worse, the syntax of the language makes it incredibly easy to create and populate dictionaries (unlike, say, in C++). Combine these two facts together and the temptation to abuse a dictionary to implement a structured data type is high.

July 4, 2013 · Tags: <a href="/tags/python">python</a>, <a href="/tags/readability">readability</a>
Continue reading (about 5 minutes)

Readability: Document your types

Wow. The previous post titled Self-interview after leaving the NetBSD board has turned out to be, by far, the most popular article in this blog. The feedback so far has been positive and I owe all of you a follow-up post. However, writing such post will take a while and content must keep flowing. So let’s get back to the readability series for now. In dynamically-typed languages1, variable and function definitions do not state the type of their arguments. This is quite convenient when writing code, but results in very hard to read “stuff” later on. Consider this snippet:

June 24, 2013 · Tags: <a href="/tags/python">python</a>, <a href="/tags/readability">readability</a>
Continue reading (about 3 minutes)

Readability: Blocks and variable scoping

In a dynamically-typed language, it is common for the scoping semantics of a variable to be wider than a single code block. For example: in at least Python and the shell, it is the case that a variable defined anywhere within a function —even inside conditionals or loops— is reachable anywhere in the function from there on. To illustrate what this means, consider this snippet in which we define a function to compute the CPU requirements needed in a database system to support a set of tables:

June 6, 2013 · Tags: <a href="/tags/python">python</a>, <a href="/tags/readability">readability</a>
Continue reading (about 4 minutes)

Silencing the output of Python's subprocess.Popen

I'm learning Python these days while writing an script to automate the testing of ATF under multiple virtual machines. I had this code in a shell script, but it is so ugly and clumsy that I don't even dare to add it to the repository. Hopefully, the new version in Python will be more robust and versatile enough to be published. One of the things I've been impressed by is the subprocess module and, in special, its Popen class. By using this class, it is trivial to spawn subprocesses and perform some IPC with them. Unfortunately, Popen does not provide any way to silence the output of the children. As I see it, it'd be nice if you'd pass an IGNORE flag as the stdout/stderr behavior, much like you can currently set those to PIPE or set stderr to STDOUT. The following trivial module implements this idea. It extends Popen so that the callers can pass the IGNORE value to the stdout/stderr arguments. (Yes, it is trivial but it is also one of the first Python code I write so... it may contain obviously non-Pythonic, ugly things.) The idea is that this exposes the same interface so that it can be used as a drop-in replacement. OK, OK, it lacks some methods and the constructor does not match the original signature, but this is enough for my current use cases! import subprocess IGNORE = -3 STDOUT = subprocess.STDOUT assert IGNORE != STDOUT, "IGNORE constant is invalid" class Popen(subprocess.Popen): """Extension of subprocess.Popen with built-in support for silencing the output channels of a child process""" __null = None def __init__(self, args, stdout = None, stderr = None): subprocess.Popen.__init__(self, args = args, stdout = self._channel(stdout), stderr = self._channel(stderr)) def __del__(self): self._close_null() def wait(self): r = subprocess.Popen.wait(self) self._close_null() return r def _null_instance(self): if self.__null == None: self.__null = open("/dev/null", "w") return self.__null def _close_null(self): if self.__null != None: self.__null.close() self.__null = None assert self.__null == None, "Inconsistent internal state" def _channel(self, behavior): if behavior == IGNORE: return self._null_instance() else: return behaviorBy the way, somebody else suggested this same thing a while ago. Don't know why it hasn't been implemented in the mainstream subprocess module.

January 5, 2009 · Tags: <a href="/tags/process">process</a>, <a href="/tags/python">python</a>
Continue reading (about 2 minutes)