Modules in Python are a nice construct to put definitions together in a single file that you will be able to reuse at any time alter on. In order to get a good module it's a good idea to follow some principles and to think about it before.
Example 14.3. A genealogy module
As an example, we want to design a module to process genealogical trees (pedigrees). This module should provide functions to build the tree and to create individuals, to register marriages and births. So first we must list the necessary operations or functions. This list should be as abstract as possible. This means that at this stage, you don't need to specify the way it will be programmed.
Let' start by listing the operations that we need to construct the tree and idividuals.
Now we need operations to query and display our tree.
We can start to build our module. We do not need to write code; we will just define the functions and their parameters, and add a docstring to these definitions. Each definition will just contain a single pass statement in order to have an executable file, that can be used for instance by the pydoc to display the whole documentation of the module. A header docstring will contain the general description of the module.
"""
A module to handle genealogy trees and families.
"""
def create_person(name, gender, spouse=None, children=[], father=None, mother=None):
"""
Returns: a dictionary (keys: 'name', 'gender', 'spouse', 'father', 'mother', 'children').
"""
pass
def register_marriage(husband, wife):
"""
If one of the person is already married, raises an error.
Updates information of each spouse.
"""
pass
def register_birth(father=None, mother=None, child_name, gender):
"""
Creates a person of name child_name and gender.
Updates information of each parents, if given.
Returns the child.
"""
pass
def grand_fathers(person):
"""
Returns the list of grand fathers.
"""
pass
def grand_mothers(person):
"""
Return the list of grand mothers.
"""
pass
def sibchip(person):
"""
Returns the list of brothers and sisters.
"""
pass
def identical(p1, p2):
"""
Boolean function: returns True if p1 and p2 are the same person,
i.e have the same name.
"""
def create_family(family, *persons):
"""
Create a list of persons, built from persons together with their
complete set of descendants.
"""
pass
def is_family_member(family, person):
"""
Boolean function that returns True if the person belongs to the family.
The test is based on the name.
"""
pass
def lookup_person(name, family):
"""
Search for a person named name in the family.
Returns None if not found.
"""
pass
def name_list(family):
"""
Returns the names of the family members as a list.
"""
def display(person):
"""
Returns a printable character strings describing the person (name,
gender, spouse, parents and children).
"""
def display_family(family):
"""
Returns a printable character strings describig the persons
belonging to the family.
"""
Let's now look at the implementation.
def create_person(name, gender, children=[], father=None, mother=None, spouse=None):
l_children = children[:]
return {'name': name, 'children': l_children, 'father': father, 'mother': mother, 'spouse': spouse}
def register_marriage(husband, wife):
if husband['spouse'] is not None:
raise Exception, husband['name'] + " is already married"
if wife['spouse'] is not None:
raise Exception, wife['name'] + " is already married"
husband['spouse'] = wife
wife['spouse'] = husband
def register_birth(father, mother, child_name, gender):
child = create_person(child_name, gender)
father['children'].append(child)
mother['children'].append(child)
child['father'] = father
child['mother'] = mother
return child
def parents(person):
return [person['father'], person['mother']]
def grand_fathers(person):
l = []
father = person['father']
mother = person['mother']
if father is not None:
if father['father'] is not None:
l.append(father['father'])
if mother is not None:
if mother['father'] is not None:
l.append(mother['father'])
return l
def grand_mothers(person):
l = []
if person['father'] is not None:
if person['father']['mother'] is not None:
l.append(person['father']['mother'])
if person['mother'] is not None:
if person['mother']['mother'] is not None:
l.append(person['mother']['mother'])
return l
def sibchip(person):
l = []
father = person['father']
mother = person['mother']
if father is not None:
for child in father['children']:
l.append(child)
if mother is not None:
for child in mother['children']:
if l.count(child) == 0:
l.append(child)
return l
def identity(p1, p2):
return p1['name'] == p2['name']
def create_family(family, *persons):
for person in persons:
if not family_member(family, person):
family.append(person)
for child in person['children']:
create_family(family, child)
def family_member(family, person):
for member in family:
if identity(person, member):
return True
return False
def lookup_person(name, family):
for member in family:
if name == member['name']:
return member
def list_names(family):
return [member['name'] for member in family]
def display(person):
if person is None:
return ""
s = "Name: " + person['name']
if person['spouse'] is not None:
s = s + "\n\t" + "spouse: " + person['spouse']['name']
if person['father'] is not None:
s = s + "\n\t" + "father: " + person['father']['name']
if person['mother'] is not None:
s = s + "\n\t" + "father: " + person['mother']['name']
if len(person['children']) > 0:
s = s + "\n\t" + "children: "
for e in person['children']:
s = s + e['name'] + " "
return s
def display_family(family):
s = ""
done = {}
for member in family:
if not done.has_key(member['name']):
s = s + display(member) + "\n"
done[member['name']] = True
return s
if __name__ == "__main__":
print "----------- test code --------------"
henri = create_person("Henri", "male")
marianne = create_person("Marianne", "female")
register_marriage(henri, marianne)
jeanne = register_birth(henri, marianne, "Jeanne", "female")
print display(jeanne)
oscar = create_person("Oscar", "male")
try:
register_marriage(oscar, marianne)
except Exception, e:
print "\n---- marriage is not possible: " + str(e) + " ----"