Python Coding Guidelines
Naming conventions
Python modules and classes: camel case starting with a capital. Example: MyPythonClass
Public python class methods: camel case starting with lower case: myPublicMethod
Private python class methods: underscore, then camel case starting with lower case: _myPrivateMethod
Python functions: all lower case with single underscores: my_python_function
Documentation is essential, but some documentation is more essential than the rest. In particular, the higher the level the documentation, the more important it is.
The most critical documentation is always at the very beginning of the python file or module, and gives the overall view of what this file or module does. Even if its only two lines, these are the most important, because everything else someone reads in your module will be placed in the context of those lines. Add the line $Id$ in this high-level documentation. Its used in version control to auto-document the revision and author (see example below).
The next most important documentation is the class documentation. It should describe the general purpose of the class, and often give a very simple usage example. It's public attributes should be listed here also (see caution about public attributes below).
The next most important documentation is the method documentation. It should fully describe the the overall purpose of the method, the inputs, the output, the effects (things it does besides creating the output), and if not obvious, the algorithm.
Finally, comes in-line documentation. If you've done a good job with documenting the higher levels above, this should not need to be copious. If a reader understands the forest, they don't need every tree explained. Adding comments that break the algorithm into sections is helpful.
Finally, python is a high-level language, so the code itself should be considered documentation. Keep every line simple, so it can be understood at a glance. Avoid cramming multiple steps into a single, hard-to-understand line.
Example:
1 """
2 Master script to process MIDAS-W incoherent scatter data.
3
4 This script assumes that data is divided into subdirectories,
5 which each contain (self-consistently) all relevant
6 information necessary for processing. Consistency checks are made to
7 ensure that all data is available before processing begins.
8
9 $Id$
10 """
11
12 import os, os.path, sys
13 import urllib2
14
15 class URIFilenameParser:
16 """URIFilenameParser is the public class used to discover filenames.
17
18 It uses a fnmatch string to find files from a URI pointing to a directory .
19
20 Usage example::
21
22 filenameParser = URIFilenameParser('http://anubis/event/2002-03-26', '[0-9]*xml')
23 filenameList = filenameParser.getFilenamesList()
24 for filename in filenameList:
25 print filename
26
27 Public attributes:
28 self.filecount - number of files found
29
30 Non-standard Python modules used: None
31
32 Written by "Bill Rideout":mailto:wrideout@haystack.mit.edu Apr. 3, 2002
33 """
34
35 def __init__(self, URI, fnmatchStr):
36 """__init__ gathers a list of filenames with the given extension from the URI string.
37
38 Inputs:
39 URI - a string representing a uri to a directory
40 fnmatchStr - a string to match file names against.
41
42 Returns: void.
43
44 Affects: initializes self.__filenameList, self.filecount
45
46 Algorithm: Use urllib2 to read page. Parse for filenames, then use fnmatch
47 module to see if they match fnmatchStr.
48
49 Exceptions: throws NoStatusDataFound if any problems loading data.
50 """
51 # initialize attributes
52 self.filecount = 0
53 self.__filenameList = []
54
55 if __name__ == '__main__':
56
57 # test this module
58 filenameParser = URIFilenameParser('http://anubis/event/2002-03-26', '[0-9]*xml')
59 filenameList = filenameParser.getFilenamesList()
60 for filename in filenameList:
61 print filename
Never write code that already exists in the standard python library. Also, use third-party pythons extensions if they are generally regarded as stable. In general, only write code directly related to your task.
Never import modules using "from". That is, always use something like import matplotlib and never from matplotlib import *. Using "from" allows you to skip using the fully-qualified path names when using the imported module, making your code shorter, but very hard to read at a later date. Caution: example code often uses "from" to import their module, in a effort to show how "simple" their module is. Note, however, that example code always just imports one module, so you always know which module is being used. In real code, you often import a number of modules, and later users will get confused as to which module any given class or method came from. So don't just cut and paste example code.
Private versus public methods in a class. When you write a class, there are two different types of methods you use, public and private. Public methods are the one meant for users of your class to call, private methods are meant for internal use only. If a method is private, its name should start with two underscores, and the first line should state that it is private. Python itself will prevent the user of your class from seeing any methods which begin with two underscores, and will throw an exception if you try to use them.
Private versus public attributes in a class. A private attribute (one you don't mean the user to directly use) should start with two underscores. Use public attributes sparingly, since the user will be able to change them without error checking. As with methods, the double underscore will remain cause an attribute to be invisible to external class users.
Catch only those exceptions you know how to handle. Try to limit your except statements to catch only those exceptions you are expecting. If you make it too general by making it catch all exceptions, you may end up treating an unexpected exception in the wrong way, and so the real error message never propagates up.