Mobile Site

Usability, the Soul of Python

An Introduction to Programming Python Through the Eyes of Usability

Jonathan's Corner (Sitemap) > Orthodox Books Online, and More > Technology > Usability, the Soul of Python: An Introduction to Programming Python Through the Eyes of Usability
Previous  1  2  3  4  5  6  7  8  9  10  Next
Printer-Friendly Version

Now suppose we want to be able to rot-13 encrypt text from Python. Rot-13 represents an extremely simple algorithm, and for the most part there is a perfectly obvious way to do it:

def rot13(text):
    result = []
    for character in unicode(text): 
        if character == u'a':
            result.append(u'n')
        elif character == u'b':
            result.append(u'o')
        elif character == u'c':
            result.append(u'p')
        elif character == u'd':
            result.append(u'q')
        elif character == u'e':
            result.append(u'r')
        elif character == u'f':
            result.append(u's')
        elif character == u'g':
            result.append(u't')
        elif character == u'h':
            result.append(u'u')
        elif character == u'i':
            result.append(u'v')
        elif character == u'j':
            result.append(u'w')
        elif character == u'k':
            result.append(u'x')
        elif character == u'l':
            result.append(u'y')
        elif character == u'm':
            result.append(u'z')
        elif character == u'n':
            result.append(u'a')
        elif character == u'o':
            result.append(u'b')
        elif character == u'p':
            result.append(u'c')
        elif character == u'q':
            result.append(u'd')
        elif character == u'r':
            result.append(u'e')
        elif character == u's':
            result.append(u'f')
        elif character == u't':
            result.append(u'g')
        elif character == u'u':
            result.append(u'h')
        elif character == u'v':
            result.append(u'i')
        elif character == u'w':
            result.append(u'j')
        elif character == u'x':
            result.append(u'k')
        elif character == u'y':
            result.append(u'l')
        elif character == u'z':
            result.append(u'm')
        elif character == u'A':
            result.append(u'N')
        elif character == u'B':
            result.append(u'O')
        elif character == u'C':
            result.append(u'P')
        elif character == u'D':
            result.append(u'Q')
        elif character == u'E':
            result.append(u'R')
        elif character == u'F':
            result.append(u'S')
        elif character == u'G':
            result.append(u'T')
        elif character == u'H':
            result.append(u'U')
        elif character == u'I':
            result.append(u'V')
        elif character == u'J':
            result.append(u'W')
        elif character == u'K':
            result.append(u'X')
        elif character == u'L':
            result.append(u'Y')
        elif character == u'M':
            result.append(u'Z')
        elif character == u'N':
            result.append(u'A')
        elif character == u'O':
            result.append(u'B')
        elif character == u'P':
            result.append(u'C')
        elif character == u'Q':
            result.append(u'D')
        elif character == u'R':
            result.append(u'E')
        elif character == u'S':
            result.append(u'F')
        elif character == u'T':
            result.append(u'G')
        elif character == u'U':
            result.append(u'H')
        elif character == u'V':
            result.append(u'I')
        elif character == u'W':
            result.append(u'J')
        elif character == u'X':
            result.append(u'K')
        elif character == u'Y':
            result.append(u'L')
        elif character == u'Z':
            result.append(u'M')
    return u''.join(result)

This is a perfectly effectively way of solving the problem, but you may wince at the thought of all that typing, and that is a good sign that this solution is not very Pythonic. Some readers may perhaps be disappointed with me (or, perhaps, not disappointed with me in the slightest) to learn that I cheated: I wrote three lines of code so Python would generate for me the long and tedious part of the routine so I could get out of such a chore, and then pasted the output into the page. We need a better solution in this.

One of the paradoxes in the programming world is that solving a problem in a more general sense may actually be less work. What we basically need is to do some translations of characters, so how can we do that? Remembering that Python's switch statement is the dictionary, we could try:

def translate(text, translation):
    result = []
    for character in unicode(text):
        if character in translation:
            result.append(translation[character])
        else:
            result.append(character)
    return u''.join(result)

This is a big improvement: cleaner, simpler, much shorter, and much more powerful. So if we are dealing with strings used to store genetic data, we can also get the complement of a string. So to get the complement of u'ATTAGCGACT', we can do:

original = u'ATTAGCGACT'
complement = translate(original, {u'A': u'T', u'T': u'A', u'C': u'G', u'G': u'C'})

And we've improved things, or at least it seems we've improved until we get around to the chore of typing out the dictionary contents for every uppercase and lowercase letter. We could write another Python snippet to autogenerate that, as the chore is not only tedious but an invitation to error, but is there a better way?

In fact there is. We can import the string library and take advantage of something that is already there, and here is a solution that is not daunting to type out, only slightly tedious, although here we must use a little ASCII:

import string
translation = string.maketrans(u'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', u'NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm')
translated = 'The quick brown dog jumps over the lazy red fox.'.translate(translation)

And with that, instead of solving the problem of translation ourselves, we have the problem already solved for us, for the most part. The variable translated is now u'Gur dhvpx oebja qbt whzcf bire gur ynml erq sbk.'

Those versed in Python's character, though, might possibly not stop here. You can make up your own forms of weak encryption, but rot-13 encoding is not the world's most obscure thing to do. Is this really the easiest and most Pythonic way to rot-13 a string? Let us fire up our Python interpreter:

>>> print u'The quick brown dog jumps over the lazy red fox.'.encode(u'rot13')
Gur dhvpx oebja qbt whzcf bire gur ynml erq sbk.

The problem is already solved for us.

A famous blog post called Python Is Not Java addresses Java programmers rather bluntly on why doing everything you'd do in Java is not getting the most out of Python:

Essentially, if you've been using Java for a while and are new to Python, do not trust your instincts. Your instincts are tuned to Java, not Python. Take a step back, and above all, stop writing so much code.

To do this, become more demanding of Python. Pretend that Python is a magic wand that will miraculously do whatever you want without you needing to lifting a finger. Ask, "how does Python already solve my problem?" and "What Python language feature most resembles my problem?" You will be absolutely astonished at how often it happens that thing you need is already there in some form. In fact, this phenomenon is so common, even among experienced Python programmers, that the Python community has a name for it. We call it "Guido's time machine", because sometimes it seems as though that's the only way he could've known what we needed, before we knew it ourselves.

Read more...

Top

Jonathan's Corner (Sitemap) > Orthodox Books Online, and More > Technology > Usability, the Soul of Python: An Introduction to Programming Python Through the Eyes of Usability
Previous  1  2  3  4  5  6  7  8  9  10  Next
Printer-Friendly Version