Our Topic: The Natural Numbers

To make this tutorial simple, we will build a small web site that lets the user visit what some people call the natural numbers: the integers beginning with 1 and continuing with 2, 3, 4, and so forth. We will define a Natural class which knows a few simple things about each number - like which number comes before it, which comes after it, and what its prime factors are.

We should start by writing a test suite for our Natural class. Not only is writing tests before code an excellent programming practice that forces you to think through how your new class should behave, but it will make this tutorial easier to understand. When you are further down in the tutorial, and want to remember something about the Natural class, you may find yourself re- reading the tests instead of the code as the fastest way to remember how the class behaves!

The reason this test will be so informative is that it is a Python “doctest”, which intersperses normal text with the example Python code. Create a file in your Grok instance named src/transient/natural.txt and give it the following contents:

A Simple Implementation of Natural Numbers

The “natural” module of this application provides a simple class for representing any postive integer, named “Natural”.

>>> from transient.natural import Natural

To instantiate it, provide a Python integer to its constructor:

>>> three = Natural(3)
>>> print 'This object is known to Python as a "%r".' % three
This object is known to Python as a "Natural(3)".
>>> print 'The number of the counting shall be %s.' % three
The number of the counting shall be 3.

You will find that there are very many natural numbers available; to help you navigate among them all, each of them offers a “previous” and “next” attribute to help you find the ones adjacent to it.

>>> print 'Previous: %r  Next: %r' % (three.previous, three.next)
Previous: Natural(2)  Next: Natural(4)

Since we define the set of “natural numbers” as beginning with 1, you will find that the number 1 lacks a “previous” attribute:

>>> hasattr(three, 'previous')
True
>>> one = Natural(1)
>>> hasattr(one, 'previous')
False
>>> one.previous
Traceback (most recent call last):
 ...
AttributeError: There is no natural number less than 1.

You can also ask a number to tell you which prime factors must be multiplied together to produce it. The number 1 will return no factors: >>> one.factors []

Prime numbers will return only themselves as factors: >>> print Natural(2).factors, Natural(11).factors, Natural(251).factors [Natural(2)] [Natural(11)] [Natural(251)]

Compound numbers return several factors, sorted in increasing order, and each appearing the correct number of times:

>>> print Natural(4).factors
[Natural(2), Natural(2)]
>>> print Natural(12).factors
[Natural(2), Natural(2), Natural(3)]
>>> print Natural(2310).factors
[Natural(2), Natural(3), Natural(5), Natural(7), Natural(11)]

Each natural number can also simply return a boolean value indicating whether it is prime, and whether it is composite.

>>> print Natural(6).is_prime, Natural(6).is_composite
False True
>>> print Natural(7).is_prime, Natural(7).is_composite
True False

Next, we need to tell Grok about this doctest. Create a file in your instance named src/transient/tests.py that looks like:

import unittest
from doctest import DocFileSuite

def test_suite():
    return unittest.TestSuite([ DocFileSuite('natural.txt') ])

You should now find that running ./bin/test inside of your instance now results in a whole series of test failures. This is wonderful and means that everything is working! At this point Grok is able to find your doctest, successfully execute it, and correctly report (if you examine the first error message) that you have not yet provided a Natural class that could make the doctest able to succeed.