Software Carpentry logo

Programming Style

April 24, 2010: We are pleased to announce that Version 4 of this course is now under development. For updates and an early peek at the content, please check out the Software Carpentry blog at http://www.software-carpentry.org/blog/.

1) Introduction

2) You Can Skip This Lecture If...

3) Reading is Learning

4) Seven Plus or Minus

5) The Mind's Eye

6) What Does This Have to Do With Programming?

7) Python Style Guide

Rule Good Bad
No whitespace immediately inside parentheses max(candidates[sublist]) max(candidates[sublist])
...or before the parenthesis starting indexing or slicing max(candidates[sublist])
No whitespace immediately before comma or colon if limit>0:printminimum,limit if limit>0:printminimum,limit
Use space around arithmetic and in-place operators x+=3*5 x+=3*5
No spaces when specifying default parameter values defintegrate(func,start=0.0,interval=1.0) defintegrate(func,start=0.0,interval=1.0)
Never use names that are distinguished only by "l", "1", "0", or "O" tempo_long and tempo_init tempo_l and tempo_1
Short lower-case names for modules (i.e., files) geology Geology or geology_package
Upper case with underscores for constants TOLERANCE or MAX_AREA Tolerance or MaxArea
Camel case for class names SingleVariableIntegrator single_variable_integrator
Lowercase with underscores for function and method names divide_region divRegion
...and member variables max_so_far maxSoFar
Use is and is not when comparing to special values ifcurrentisnotNone: ifcurrent!=None:
Use isinstance when checking types ifisinstance(current,Rock): iftype(current)==Rock:

Table 37.1: Basic Python Style Rules

8) Naming

9) Scope and Size

10) The Difference It Makes

import sys, os
import reader, splitter, transpose
a=[]
b=[]
c=[]
d=sys.argv[1]
a=reader.rdlines(d)
b=splitter.splitsec(a)
c=d.split('.')
for i in range(len(b)):
    if os.path.isfile('%s.%d.dat'%(c[0],i+1)):
        print '%s.%d.dat already exists!'%(c[0],i+1)
        break
    else:
        output=file('%s.%d.dat'%(c[0],i+1),'w')
        print>>output,transpose.txpose(b[i])
        output.close()
import sys, os
import reader, splitter, transpose

input_file_name = sys.argv[1]
lines = reader.read_lines_from_file(input_file_name)
sections = splitter.split_into_sections(lines)
file_name_stem = input_file_name.split('.')[0]
for i in range(len(sections)):
    output_file_name = '%s.%d.dat' % (file_name_stem, i+1)
    if os.path.isfile(output_file_name):
        print '%s already exists!' % output_file_name
        break
    else:
        output = file(output_file_name, 'w')
        print >> output, transpose.transpose(sections[i])
        output.close()

11) Function Length

12) What Does This Function Do?

# What's missing, and what's extra?
def diff_filelist(dir_path, manifest,
                  ignore=[os.curdir, os.pardir, '.svn']):

    def show_diff(title, diff):
        if diff:
            print title
            for d in diff:
                print '\t' + d

    expected = Set()
    inf = open(manifest, 'r')
    for line in inf:
        expected.add(line.strip())
    inf.close()

    actual = Set()
    contents = os.listdir(dir_path)
    for c in contents:
        if c not in ignore:
            actual.add(c)

    show_diff('missing:', expected - actual)
    show_diff('surplus:', actual - expected)

13) Ways to Answer the Question

14) Other Sources of Information

if __name__ == '__main__':
    if len(sys.argv) != 3:
        print >> sys.stderr, "usage: diff_filelist directory_path manifest_file"
        sys.exit(1)
    diff_filelist(sys.argv[1], sys.argv[2])

15) Idioms

count = 0
while 1:
    line = infile.readline()
    if not line:
        break
    count += 1

16) Learning Idioms

17) Style Tools

18) Python Style Tools

19) Documentation

20) More On Documentation

21) Traceability

__version__ = "$Revision: 423$"

if __name__ == '__main__':
    print __version__

22) Tracing Data

# $Revision: $
# From: biomes.dat version 421
# By: ecoanalyzer.py version 37
# Parameters: sliding_average 20 trim False
# On: 2006-02-22 12:14:07 EST

23) Embedding Documentation

/**
 * Returns the least common ancestor of two species based on DNA
 * comparison, with certainty no less than the specified threshold.
 * Note that getConcestor(X, X, t) returns X for any threshold.
 *
 * @param left        one of the base species for the search
 * @param right       the other base species for the search
 * @param threshold   the degree of certainty required
 * @return            the common ancestor, or null if none is found
 * @see               Species
 */
public Species getConcestor(Species left, Species right, float threshold) {
    ...implementation...
}
<p><strong>getConcestor</strong></p>

<p><code>public&nbsp;Species&nbsp;getConcestor(Species&nbsp;left,&nbsp;Species&nbsp;right,&nbsp;float&nbsp;threshold)</code></p>

<blockquote>

<p>Returns the least common ancestor of two species based on DNA
comparison, with certainty no less than the specified threshold.  Note
that getConcestor(X, X, t) returns X for any threshold.</p>

<p><strong>Parameters:</strong></p>
<blockquote>
<p><code>left</code> - one of the base species for the search</p>
<p><code>right</code> - the other base species for the search</p>
<p><code>threshold</code> - the degree of certainty required</p>
</blockquote>

<p><strong>Parameters:</strong></p>
<blockquote>
<p>the common ancestor, or null if none is found</p>
</blockquote>

<p><strong>See Also:</strong></p>
<blockquote>
<p><code>Image</code></p>
</blockquote>

</blockquote>

24) Docstrings

'''This module provides functions that search and compare genomes.
All functions assume that their input arguments are in valid CCSN-2
format; unless specifically noted, they do not modify their arguments,
print, or have other side effects.
'''

__version__ = '$Revision: 497$'

def get_concestor(left, right, threshold):
    '''Find the least common ancestor of two species.

    This function searches for a least common ancestor based on DNA
    comparison with certainty no less than the specified threshold.
    If one can be found, it is returned; otherwise, the function
    returns None.  get_concestor(X, X, t) returns X for any threshold.

    left      : one of the base species for the search
    right     : the other base species for the search
    threshold : the degree of certainty required
    '''

    pass # implementation would go here
>>> import genome
>>> print genome.__doc__
This module provides functions that search and compare genomes.
All functions assume that their input arguments are in valid CCSN-2
format; unless specifically noted, they do not modify their arguments,
print, or have other side effects.
 
>>> print genome.get_concestor.__doc__
Find the least common ancestor of two species.

    This function searches for a least common ancestor based on DNA
    comparison with certainty no less than the specified threshold.
    If one can be found, it is returned; otherwise, the function
    returns None.  get_concestor(X, X, t) returns X for any threshold.

    left      : one of the base species for the search
    right     : the other base species for the search
    threshold : the degree of certainty required

25) Summary