There are a number of different ways to format python code. Many programmers abuse this freedom and write code that is difficult to read and thus hard to maintain. While there is more than one way to properly format code, here is a set of guidelines which I have found useful in practice. You are not required to abide by them religiously, but I will take marks off for poor formatting. Some of these guidelines may seem amazingly anal, but they really make a difference when reading code.
In the following, each item has a code associated with it to the left of the description of the item. I will use this code to specify the problem when correcting your code. It is up to you to match the code with the item. Hopefully this will encourage you to read this style guide :) As a general rule, the earlier items in a section are more important than the later ones and/or represent more common errors.
In addition, to help catch the simplest style violations I have an automatic style checker program. It won't catch all style errors by any means, but it will catch many of the more common ones. You should run your code through the style checker before you submit it; if it fails, You need to make changes until your code passes, or you convince me that there is a bug in the checker. The python style checker is written (of course) in python ;).
Here is what you have to do to get the style checker working:
Download the style checker from this
page onto your home machine. The easiest way to do this is to come
to the CS lab, log on to a computer, start a web browser (e.g.
Firefox), surf to this page, and then do "Save Page As" in the "File" menu
(this works for Firefox; other browsers have similar commands). It will
suggest you save the file under the name python_style_check.py
and
you should agree. This will put the style checker program into one of your
directories or on a disk.
Start up IDLE for Python. Under the File menu, select Open... and find
where you saved python_style_check.py
. Open this file.
Now go to the Run menu and run the module (alternately you can hit F5).
This will start the file checker. Input the name of the file you want to check.
If it is in the same directory as the python_style_check.py
program,
you only have to type in the name of the file, otherwise put in the full path to the file.
If you file is found, the style checker will report any errors found in your program.
Don't be alarmed if there are a lot of errors reported; just go through the file and fix them. Some lines will probably have multiple style violations; you should fix all of them. You'll probably hate this program at first, but your code will become much more readable as a result. If you think you've found a bug in it, let us know at once; this is a work in progress. Note that the style checker may sometimes be too stupid to know when it's in the middle of a comment or a literal string, so it may report errors that aren't really errors in those cases. If so, just disregard them.
These mistakes occur so often that they're almost universal. Therefore, please pay particular attention to avoiding them. Follow the links to get to the descriptions below. Style mistakes followed by an asterisk (*) are caught by the style checker.
Never, ever, ever use the tab character (ascii 0x9)! Different people use different tab settings, and code that looks just fine with a tab width of 2 becomes illegible with a tab width of 8. IDLE should make the proper tabs for you and save them as spaces. If you write your code somewhere else, be on the lookout for errant tabs.
ALWAYS surround these binary operators with a single space on either side: assignment (=, +=, etc.), comparisons (==, <, >, !=, <>, <=, >=, in, not in, is, is not), booleans (and, or, not), and arithmetic operators. Example:
i = j + 1 # NOT i=j+1 submitted += 1 # NOT submitted+=1 x = x * 2 - 1 # NOT x=x*2-1 hypot2 = x * x + y * y # NOT hypot2=x*x+y*y c = (a + b) * (a - b) # NOT c=(a+b)*(a-b)
Some people prefer to omit the space around * or / but leave it around + and - as a hint about precedence, but we discourage this. However, it's OK to leave out spaces in array subscripts for simple increments/decrements:
b = a[i-1]
Unfortunately the current version of the style checker will flag this anyway.
Always put a space after a comma.
There are still many devices around (especially printers) that are limited to 80 character lines. The default wrapping on such devices looks ugly. Therefore, please limit all lines to a maximum of 78 characters.
The preferred way of wrapping long lines is by using python's implied line continuation inside parentheses, brackets and braces. If necessary, you can add an extra pair of parentheses around an expression, but sometimes using a backslash looks better. Make sure to indent the continued line appropriately. Some examples:
class Rectangle(Blob): def __init__(self, width, height, color='black', emphasis=None, highlight=0): if width == 0 and height == 0 \ and color == 'red' and emphasis == 'strong' \ or highlight > 100: raise ValueError, "sorry, you lose" if width == 0 and height == 0 and (color == 'red' \ or emphasis is None): raise ValueError, "I don't think so" Blob.__init__(self, width, height, color, emphasis, highlight)
In some cases, explicit line continuation characters are unnecessary. When in doubt, use them anyway. Also, for long chains of booleans (a and b and c...) try to put the "and" or "or" at the start of a line rather than at the end of a line; this makes it clear that the expression is continued from the last line.
The identifiers you use for variable names and modules should all be lowercase. If you have more than one word in the identifier, separate them by underscores, like this:
foo foo_bar big_foo_bar
For class names, these should begin with a Capital letter and otherwise be lowercase, such as:
Rectange Large_Water_Bottle
Separate top-level function and class definitions with at least two blank lines. We like to separate method definitions inside a class by two blank lines as well. but one is sometimes OK. Extra blank lines may be used to separate groups of related functions (but don't overdo it). It's also good to put comments to separate groups of functions e.g.
# These functions provide internet access for the Widget class.
For really significant sections, or for class headers, do this:
# # The class Widget implements objects that can do all kinds of neat # stuff. #
I.e. have one empty comment line at the top and bottom of the header.
For long functions, or long sections within a function, it is often a good idea to have comments at the end of the function/block, e.g.
def foobar(x, y, z): # 2000 lines of code follow... return 1 # end foobar
Similarly, you can have "# end if", "# end while", etc. A better solution is to keep functions and blocks short enough so that this isn't needed.
Use blank lines in functions to indicate logical sections. We also like to have blank lines before each if/while/for statement to set them off logically from the rest of the surrounding code, which we find makes the code more readable.
Do not put large numbers of empty lines (> 2) between code sections unless there is a clear need to distinguish different sections of the code.
Indentation levels should be consistent. We prefer 4 spaces for one indent level.
Avoid putting a large number into a file which has no obvious relevance to the surrounding code. This is known as a "magic number". Instead, define it as a variable at the top of the file.
Don't put in code that has no function or no effect. If it's code that's was only used for debugging purposes, it should be removed before you submit your lab.
Do not put multiple statements on one line, not even very simple ones. It's just confusing and hard to read. Similarly, we dislike this:
if not line: break
and prefer:
if not line: break
Remember: there is no tax on newlines. Do not try to cram as much as you can on one line.
Don't use whitespace in the following places:
Immediately inside parentheses, brackets or braces, as in:
spam( ham[ 1 ], { eggs: 2 } )
Always write this as:
spam(ham[1], {eggs: 2})
Immediately before a comma, semicolon, or colon, as in:
if x == 4 : print x , y x , y = y , x
Always write this as:
if x == 4: print x, y x, y = y, x
Immediately before the open parenthesis that starts the argument list of a function call, as in
spam (1)
Always write this as
spam(1)
Immediately before the open parenthesis that starts an indexing or slicing, as in:
dict ['key'] = list [index]
Always write this as
dict['key'] = list[index]
Excessive amounts of space around an assignment (or other) operator to align it with another, e.g.:
x = 1 y = 2 long_variable = 3
A good rule of thumb is: if you have to move the operator eight or more spaces, don't waste your time. Otherwise, do the alignment. E.g., change:
x = 1 foo = 2 fudge = 5
to
x = 1 foo = 2 fudge = 5
but leave
x = 1 y = 2 this_variable_name_is_really_long = 3
alone. This is a bit of a judgment call.
Don't use spaces around the '=' sign when used to indicate a keyword argument or a default parameter value. For instance, instead of:
def complex(real, imag = 0.0): return magic(r = real, i = imag)
write:
def complex(real, imag=0.0): return magic(r=real, i=imag)
This may make the style checker complain; don't worry about it. The style checker isn't perfect.
Use parentheses to show operator precedence in all cases except that of multiplication/division over addition/subtraction and assignment statements.
Always place import statements at the top of your program, right beneath the docstring and header comment. Import statements should never be in the middle of your program.
In general, avoid using "from X import *"; either do this:
from X import Y # For a single function that's used a lot.
or do this:
import X # For a module where we need a lot of functions.
Also, do not use "import X" or "from X import Y" inside a class or function. We've never seen a case where it's necessary, and it just makes things confusing. Put all import statements at the toplevel and at the beginning of the file. That way, we know where to look for them. It's up to you whether to format them as
import X, Y, Z
or
import X import Y import Z
We tend to use the former for quick throwaway scripts and the latter for larger projects.
Each of your files should include the standard header comment, detailing the name of the file, your name, the course name, and anything else you feel is relevant to understanding your code. You should format your header comment like this:
############################## # CSC 207 Fall 2008 # Mark Goadrich # Drake Equation ##############################
If a comment is a phrase or sentence, its first word should be capitalized, unless it is an identifier that begins with a lower case letter (never alter the case of identifiers!). We prefer comments that are complete sentences. You should use two spaces after a sentence-ending period. Ideally, refer to identifiers with surrounding quotes, e.g.
# The variable 'nitems' represents the number of items in the stack.
If a comment is very short, it doesn't have to be a full sentence or end in a period e.g.
i = 1 # loop index
This is called an "inline comment". Use these only when describing something i.e. in the above code snippet you're saying "The variable 'i' represents a loop index."
Comments should be correctly spelled (no typos) and be grammatically correct. We don't want to sound like your high school English teacher, but it's rilly unplesant to read coments that hav speling or grmatacial or tpyogarphic rrors.
Always leave a space after the open-comment sign, e.g.
# This comment is easy to read. #This comment is harder to read.
Write comments for anything that isn't completely obvious from the context. In particular, write comments for any tricky algorithm or code you are using. Also put a comment at the beginning of each function describing what it does. When in doubt, comment more rather than less.
Comments should not restate the obvious. This is especially common with inline comments. Example:
x = x + 1 # increment x
Don't make meaningless comments e.g.
i = 1 # i
Don't laugh; we've actually seen this sort of thing.
Comments that contradict the code are worse than no comments. ALWAYS MAKE A PRIORITY OF KEEPING THE COMMENTS UP-TO-DATE WHEN THE CODE CHANGES!
Always indent your code to the same degree as the surrounding code.
Try to line up inline comments where convenient. In other words, don't do this:
x = x + 1 # some cool comment about x y = y + 1 # some even cooler comment about y
Instead, do this:
x = x + 1 # some cool comment about x y = y + 1 # some even cooler comment about y
Do not write comments that apply to the preceding code if you can possibly avoid it. Try to write comments that refer to the current line of code or to the lines of code which immediately follow.
Block comments generally apply to some (or all) code that follows them, and are indented to the same level as that code. Each line of a block comment starts with a # and a single space (unless it is indented text inside the comment). Paragraphs inside a block comment are separated by a line containing a single #. Block comments are best surrounded by a blank line above and below them (or two lines above and a single line below for a block comment at the start of a a new section of function definitions). We always like to start and end a block comment with a line containing a single #; this is a matter of personal preference. In other words, a block comment looks like this:
# # The first line comes after an empty line. # # Separate paragraphs are also separated by an empty line, # and there's an empty line at the end. #
Block comments at the top of a file or at the beginning of a class or function should be turned into docstrings (see below).
All modules should normally have docstrings, and all functions and classes exported by a module should also have docstrings. Public methods (including the __init__ constructor) should also have docstrings. When in doubt, add a docstring to all functions. Otherwise, you'd have to add a comment indicating the purpose of the function anyway, so why not have docstrings?
The docstring of a script (a stand-alone program) should be usable as its "usage" message, printed when the script is invoked with incorrect or missing arguments (see above).
For consistency, always use """triple double quotes""" around docstrings. This allows the docstring to span multiple lines.
Don't hesitate to decompose your functions into lots of smaller functions where appropriate. Don't write functions that are pages and pages of text in length.
Don't do this:
try: # code goes here except: # catch all exceptions pass
If you plan to implement error handling code that is specific to the current situation, but don't want to do it now, write
try: # code goes here except: # catch all exceptions raise # reraise the exception
and rely on your code up-stack of this module to catch the error and deal with it in a generic way. Even better, do this for each exception individually and add a comment to the effect that you need to fix this later:
try: # code goes here except FooError: # FIXME: implement proper error handling later. raise FooError # reraise the exception
If you don't want to deal with errors at all, don't put a 'try: except:' condition in at all, but add a comment for later:
# FIXME: catch FooError that could be raised by function bar().