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.