← Thankful Friday | A bunch of old posts →

Stylish Programming in Python, Part 1

Say What You Mean

Last time, in Stylish Programming in Python, Part 0: Get It Done, we wrote a command line utility that takes a weight in pounds as input as prints out the same weight, converted to kilograms.

The code looks like this:

import sys

while 1:
    input = raw_input()
    try:
        x = float(input)
    except ValueError:
        sys.exit()
    y = x / 2.2
    print y

It works just fine, but it doesn't communicate its intention very well. What's x? What's y? Why does the program divide our input by that surprisingly precise number? What's causing the program to exit in the middle? We can answer those questions fairly easily just by changing the names of a few variables.

import sys

while True:
    data = raw_input()
    try:
        pounds = float(data)
    except TypeError:
        # If the user enters something that's not a number, exit gracefully.
        sys.exit()
    kilograms = pounds / 2.2
    print kilograms

There. All we've done so far is rename a couple of variables, and added a comment but suddenly the purpose of the code is clear to any programmer. Comments can be quite useful for explaining why something is happening when the code doesn't explain itself, but generally shouldn't be used to explain what the code is doing. The code itself should be written in such a way that it's effects are clear on their own. Too many comments can be a form of clutter. In this case, our comment tells us why we might expect to catch an exception at that point in the code.

It's starting to look good. However, when a user runs this code, they see the following:

$ python converter.py
_

It's not very clear what is expected of the user. Even if they figure out what they're supposed to do with that blank line, they'll get something like this:

$ python converter.py
200
90.9090909091
$ _

Nothing here tells the user how the output relates to the input. So let's add some helpful prompts:

import sys

while True:
    data = raw_input('How much do you weigh in pounds? ')
    try:
        pounds = float(data)
    except TypeError:
        sys.exit(0)
    kilograms = pounds / 2.2
    print "You weigh %f kilograms" % kilograms

Much better. Now the user sees this:

$ python converter.py
How much do you weigh in pounds? 200
You weigh 90.9090909091 kilograms
q
$ _

The meaning behind the input and output are clear, but there are still a few usability issues.

  1. It's too verbose now. The most important information is hidden in a wall of text. We want to foreground the information that is most relevant to the user, while still providing enough supporting information that they know what is going on.
  2. It may be that the user doesn't care about their weight; they just want to convert some weight. Maybe it's the weight of their dog, a barbell or a truck. There's nothing about the code that constrains it to converting only human weights, and there shouldn't be anything in the interface that constrains it either.
  3. The precision of the result is inappropriate. There are so many digits, it is hard to take in at a glance. This inhibits readability. So lets shorten it to only show tenths of a kilogram.

Addressing all these issues, we come up with the following:

import sys

while True:
    data = raw_input('Weight in lbs: ')
    try:
        pounds = float(data)
    except TypeError:
        sys.exit(0)
    kilograms = pounds / 2.2
    print "Weight in kg: %.1f" % kilograms

The prompt and the output are much more terse now, but no less clear.

$ python converter.py
Weight in lbs: 200
Weight in kg: 90.9
$ _

Naming is an incredibly important part of programming. Good variable names can mean the difference between readable, usable code and an inscrutable nightmare. It's important to note, however, that longer variable names are not always better. Shorter is not always better either. Here are a few handy guidelines:

  • Be descriptive. Bytes are cheap, and there is no reason to be stingy when naming your variables. single letter variable names should, in most cases be avoided. If you need a loop index, it's probably okay to name it i, or j, but otherwise, give it a proper name, so that your code is readable.
  • Be consistent. Don't name one variable kg and another one millimeter. Other bad pairs: color/odour, cats/dog, big_fish/littlefish.
  • Don't use abbreviations, unless they are extremely standard. It's okay to call your CSV file csv, but good luck remembering if that password variable was pass, passwd, psswrd, or pwd)
  • Be specific. The nature of an object named document is easier to discern than that of one named item.
  • Be accurate. While employee might be a more specific name than person, if the object pointed to may or may not actually be an employee, it might be better to name it person.
  • Be consistent, not just in naming, but in your use of case. If you're programming in python, I recommend following the conventions of PEP-8.

Most importantly, name your variables thoughtfully. Though it will have no effect on the way your code runs, you will thank yourself later. It can mean the difference between being able to find bugs easily when they crop up, and spending hours or days trying to hunt them down.

In the next installment of Stylish Programming in Python, we'll start exploring ways of actually structuring your code so that it can be easily repurposed, and to minimize duplication of code. We will see how structure and expressive power are related. This is where programming really starts to get interesting. Stay tuned

Comments !