Python Programming Style Guide

 

Program Structure

Python Style GuideStatement Structure

Python is very flexible in terms of program structure. That is, the syntax does not require a specific ordering to functions or classes within a module or methods within a class. (Note, however, that functions and classes must be defined before they can be used.) But large programs can quickly become unmanageable and difficult to read. This section outlines several requirements in terms of program structure.

The Main Driver

The Python source file that contains the starting point or the first instruction to be executed is known as the driver module. There are two styles that can be used for organizing the driver module, depending on whether functions are used. In no case should a class be defined within the driver module.

Driver Without Functions

The first statement to be executed is the first statement at file level (outside all functions and class definitions). For simple drivers that do not need to be organized into multiple functions, all statements can be at file level as illustrated by the sample program below. For this style, which does not include any function definitions, you are to use the following structure:

  • All import statements that are needed by code within the driver should be specified immediately following the file header.
  • Constant variables, if any, should be specified after the import statements.
  • The executable statements follow the constant variables.
#----------------------------------------------------------
# sample.py
#
# Created by: John Q. Smith
#
# A simple program that prompts for a real value and computes
# its square root.
#----------------------------------------------------------

x = float( input("Enter a real value:") )
y = math.sqrt( x )
print( "The square root of", x, "is", y )

Driver With Functions

Large driver modules should be organized into multiple functions and include a main() routine. The order in which functions are listed within a file is not important, but the order of executable statements at file level is. When subdividing a program into various functions using a top-down design, it is good programming practice to place all executable statements within functions and to specify one function as the main routine, as illustrated in diceroll.py program below. With this approach:

  • The main function, which is commonly named main() due to that name being used in other languages, should be defined first.
  • All remaining functions definitions must follow, in any order.
  • At the bottom of the file, a single file-level statement (not including constant variables) is used to call the driver function.
  • All function definitions must follow any import statements and constant variables that are defined after the file header.
#----------------------------------------------------------
# diceroll.py
#
# Created by: R. Necaise
#
# Simulates the rolling of two dice.
#----------------------------------------------------------

from random import *

 # Minimum number of sides on a die.
MIN_SIDES = 4    

 # Our very own main routine for a top-down design.
def main():
  print( "Dice roll simulation." )
  numSides = int( input("How many sides should the die have? ") )  
  if numSides < MIN_SIDES :
    numSides = MIN_SIDES
  value = rollDice( numSides )
  print( "You rolled a", value )

 # Simulate the rollowing of two nSided dice.  
def rollDice( nSides ):
  die1 = randint( 1, nSides + 1 )
  die2 = randint( 1, nSides + 1 )
  return die1 + die2

 # Call the main routine which we defined first.
main()

Modules

Modules can contain any combination of function and class definitions, constant and non-constant variable declarations and executable statements. In this course, all non-driver modules will be limited to class definitions and constant variable declarations and should be organized as follows:

  • Specify all import statements that are needed by code within the driver immediately following the file header. Note, if a module is not directly needed by this module, it should not be imported.
  • Constant variables, if any, should be defined after the import statements.
  • The class definitions should follow the constant variables, if any.

One Public Class. If a module contains a single public class:

  • The public class should be listed first.
  • Followed by any private or storage classes.

For example, the following code segment illustrates the definition of two classes, one public and the other private.

#----------------------------------------------------------
# linearbag.py
#
# Implementation of the Bag ADT using a Python list.
#----------------------------------------------------------

class Bag :
   # Constructs an empty bag.
  def __init__( self ):
    self._theItems = list()
      .....

  def __iter__( self ):
    return _BagIterator( self._theItems )


# Defines the iterator used with a Bag.
class _BagIterator :
  ......

Multiple Public Classes. If a module contains multiple public class definitions:

  • Any storage or other private classes used by the public class can be defined immediately after the public class.
  • Each additional public class, along with its private or storage classes will follow the first group.

The following code segment illustrates a module containing several public classes, all of which are related to array definitions.

#----------------------------------------------------------
# array.py
#
# Implementation of the various array structures.
#----------------------------------------------------------


# Defines a 1-D array implemented using hardware supported arrays.
class Array :
  ......

# Defines a 2-D array implemented as an array of arrays.
class Array2D :
  ......

# Defines a multi-dimensional array using a single 1-D array and
# row-major ordering.
class MultiArray :
  ......

Classes

To aide in readability and understanding of a class definition, the class should be well structured and documented. The comments required for a class and its methods are described in the "Comments" section.

Organization. The methods defined for a class can technically occur in any order. To provide a well structured implementation and to aide the reader, you are to use the following structure:

  • Class constants, if any, should be defined first.
  • The constructor should be the first method defined.
  • The public methods should follow the constructor.
  • The special __iter__() method should be listed after all other public methods.
  • Helper methods (private methods), if any, should be at the bottom.

Leave at least one and no more than two blank lines between the method definitions. The following example illustrates a fully commented and well structured class definition.

# -----------------------------------------------------------------------
# Defines a point in the 2-D Cartesian coordinate system. The points can
# be either integers or floating-point values.
# -----------------------------------------------------------------------

class Point :
   # Creates a point object from the supplied coordinates.
  def __init__( self, x, y ):
    self._xCoord = x  
    self._yCoord = y  

   # Returns the x coordinate of the point.
  def getX( self ):
    return self._xCoord

   # Returns the y coordinate of the point.
  def getY( self ):
    return self._yCoord

   # Computes and returns the distance between this point and the otherPoint.
  def distance( self, otherPoint ):
    xDiff = self._xCoord - otherPoint._xCoord
    yDiff = self._yCoord - otherPoint._yCoord
    return math.sqrt( xDiff ** 2 + yDiff ** 2 )

   # Determines if this point is the same as the otherPoint.
  def __eq__( self, otherPoint ):
    return self._xCoord == otherPoint._xCoord and self._yCoord == otherPoint._yCoord

Storage Classes

A storage class is used to create objects for simply storing structured or multi-component data items. Typically, they only contain a constructor used to create and initialize the various data fields. Any class or code segment that has access to the storage class can directly reference the various data attributes.

# -----------------------------------------------------------------------
# Defines a private storage class for use with the Map ADT implemented
# using a Python list.
# -----------------------------------------------------------------------

class MapElement :
  def __init__( self, key, value ):
    self.key = key
    self.value = value
  • Storage classes should be defined within the same module in which they will be used.
  • The data attributes of a storage class should be defined as public and thus not include the preceding underscore as used with other classes.
  • The visibility status (public or private) of the storage class should be clearly stated in the class description. A private storage class should not be imported into any other module.



Python Style GuideStatement Structure
Print -- Recent Changes
Page last modified on September 06, 2012, at 11:53 AM