The Irritating Python guide

Inspired by Roedy Green’s legendary unmaintainable code and discussions with eoinmcl and #netsoc at large, I realised that a new age of readability in code was upon us. Languages such as Python make it disgustingly easy to read programs, even without a prior knowledge of the language! As I looked down from my ivory tower upon the legions comprehending the sweat of my brow with ease I realised that it was time for a change. And so this tome was assembled, bits conveyed on the skins of a million broken PHP coders.

Disclaimer: Before I begin I must admit that this guide is not exhaustive. It mostly takes things that I’ve found or broken along the course of my gradual descent into Python-reliance. I try to avoid using large blocks of obscure code and grotesque blocks of maps, ords and lambdas - I’m trying to show bits and pieces of code that can be mashed together to create such nightmares. I’m still learning and make no claim to even be an intermediate-level Python coder.

Python offers the user a variety of features that make coding forgiving, clean and extensible. Mercifully, these features can be used for evil means.

Abusing the type system

Python’s type system is forgiving and blind. You don’t have to think twice about ways to abuse this. Built-in functions like “int” and “str” are yours to destroy minds with. This can be very simply done at first:

>>>str
<type ’str’>
>>>int
<type ‘int’>
str = int
>>>str(23)
23

This is fairly simple stuff to begin with, but even such simple assignments can fuddle the minds of observers with little concentration when applied correctly - this is where “del” comes into play. In the above example a simple “del(str)” will remove the reassigned str and return it to the string builtin function. This makes it easy to bounce back and forth between meanings.

It’s a more obvious breakage when it comes to code flow, but variables should not be forgotten either - str can be reassigned to be “2″ or even {”yes”: 2}.

To the uninitiated lambda functions are baffling globs of magic goo. This can be used to your advantage: Doing things like the following can lead to great confusion:

>>>str = lambda i: __builtins__.str(i + 2)
>>>str(33)
‘35′

Not only do you end up with an incorrect number, the number is a valid string.

More fundamental torture can be achieved by assignments as simple as “True = False”. Yes, you can do that.

Incomprehension

List comprehensions are useful and tidy ways to get a lot of stuff done quickly without cluttering code. They can make code hard to read at times but once you become trained in using them they become demystified quite a bit. However, there are nasty tricks beyond the initial readability issues. Python’s whitespace-affinity baffles many - I know more than a few people who started learning from a popular text that neglects to mention the importance of indentation for a few chapters of examples. And as they say, a little knowledge is a dangerous thing. List comprehensions can be spaced out, ignorant of whitespace. This can lead to code like this:

m = [ i * i for i in range( 20 ) ]

Mostly this is just ugly as hell. However, if you get a little creative you can mix list comprehensions with indented functions and conditionals to create seemingly elegant but entirely misleading code.

Keep it ambiguous

Make sure that your code exits at the right point - there are a few ways to exit nicely in Python, but they’re no fun. Make sure your program makes use of “exit” wherever possible - make sure not to use “exit()”!

Similarly, random numbers and string literals (moreso) will add a delightful element of confusion to your code. As ever, bury your definitions of such things in imported modules and submodules. A line that says “remove_negative_elements_from_all_lists” (that actually equals “omghax0r”) by itself that does nothing in reality can really make you scratch your head.

Similarly, little mean allusions to other programming languages can only add to the fun. Make sure to make a “main()” function filled with interesting looking code - you could even make it readable. However, you also need to make sure to never call that main(), import a module that imports your module and then does something completely different with the functions defined in it.

Tuples and Lambda functions

Lambda functions are functions right? They take arguments just like anything else - Almost. I made this error myself a few dozen times before I became aware of it due to sheer frustration. One should always take advantage of the fact that

>>> charfind = lambda a, b: a in b

Is most definitely not the same thing as

>>> charfind = lambda (a, b): a in b

Getting docstrung up

Deployed properly, docstrings make python code much more friendly on the eyes, easily documented and coherent. Too bad you’re not interested in that.

Admittedly, the abuse of docstrings is limited by syntax highlighting in most editors - the sections that are docstrings will stand out like large, green sore thumbs (in emacs at least). This might raise suspicions amongst those with a clue, but it doesn’t stop you from abusing this fact. Be sure to throw some code into your docstrings and later call it from the depths of another function like so:

>>>eval(otherfunction.__doc__)

The import of imports

The original inspiration for me writing this guide was some unintentional awful code I had created, left lie and come back to. However, the motivation for writing it came from imports. I despise obscure imports. If you import perfectly good modules with random “simplified” names, I mentally defecate on you from a considerable height. However, just because it’s stupid in real life doesn’t mean you can’t be mean with it.

The horror of using from re import compile as os style imports is obvious. Engineering your imports to contain similar function names is a definite multiplier for the horror - for example, import the re module’s compile() function as compile() and then rewrap it to actually call the builtin compile() function.

If you have a lot of time to waste you could get really dirty with your imports and create some wrappers for your fake module. Python’s introspection features can be used to create some bizarre-looking code that does some pretty awful things. The following line is something I cooked up that could be wrapped in a generator function to return arguments of a particular number of arguments. This means that a random function from a module will be returned which you can exec that will take the same number of arguments.

>>>import re
>>>import inspect
>>>argnum = 2
>>>filter(lambda (a, b): a == argnum, [ (getattr(re, function).func_code.co_argcount, function) for function in dir(re) if inspect.isfunction(getattr(re,function))])

This is almost downright malicious when you think about the implications of the “os” module or something similar being switched around.


About

Hugh Nowlan is recovering from Trinity Collge Dublin’s Computer Science course, while undergoing said course. He writes code, makes music and takes photos.

If you’re really THAT interested you can find out a bit more about me at the various sites I have surrendered spurious personal information with below.

I have worked here, here and here and am now professionally unemployed. I admin for these nice people. I go to college here. It sucks.

If Inky did album covers and I did bad grindcore this would be me.

Flickr Photos

Zippo in candlelightZippo in candlelightiPod in candlelightSad signRathgar Church

View All Photos