Let's look at a simple, but complete program file. The program
simulates several dice throws. We've decided that the command-line
synopsis should be:
dicesim.py
〈-v〉 〈-s
samples
〉
The -v
option leads to verbose
output, where every individual toss of the dice is shown. Without the
-v
option, only the summary statistics are shown. The
-s
option tells how many samples to create. If this is
omitted, 100 samples are used.
Here is the entire file. This program has a five-part design
pattern that we've grouped into three sections.
Example 35.1. dicesim.py
#!/usr/bin/env python
"""dicesim.py
Synopsis:
dicesim.py [-v] [-s samples]
-v is for verbose output (show each sample)
-s is the number of samples (default 100)
"""
import dice, getopt, sys
|
Docstring. The docstring provides the synopsis of the program, plus
any other relevant documentation. This should be reasonably
complete. Each element of the documentation is separated by
blank lines. Several standard document extract utilities
expect this kind of formatting.
|
|
Imports. The imports line lists the other modules on which this
program depends. Each of these modules might have the
main-import switch and a separate main program. Our objective
is to reuse the imported classes and functions, not the main
function.
|
def dicesim( samples=100, verbose=0 ):
d= dice.Dice()
t= 0
for s in range(samples):
n= d.roll()
if verbose: print n
t += n
print "%s samples, average is %s" % ( samples, t/float(samples) )
|
Actual processing in dicesym. This is the actual heart of the program. It is a pure
function with no dependencies on a particular operating
system. It can be imported by some other program and
reused.
|
def main():
samples= 100
verbose= 0
opts,operands= getopt.getopt( sys.argv[1:], "vs:" )
for o,v in opts:
if o == "-v": verbose = 1
elif o == "-s": samples= int(v)
dicesim( samples, verbose )
if __name__ == "__main__":
main()
|
Argument decoding in main. This is the interface between the operating system that
initiates this program and the actual work in
dicesym . This does not have much reuse
potential.
|
|
Program vs. import switch. This makes the determination if this is a main program
or an import. If it is an import, then
__name__ is not
"__main__" , and no additional processing
happens beyond the definitions. If it is the main program, the
__name__ is "__main__" ;
the arguments are parsed by main , which
calls dicesym to do the real work.
|
This is a typical layout for a complete Python main progam. There
are two clear objecives. First, keep the main
program focused; second, provide as many opportunities for reuse as
possible.