CS8, Fall 2010

lab05: ("lab five")
Predicate functions and functions on lists


Goals for this lab

By the time you have completed this lab, you should be able to lots of interesting things with strings and lists in Python

In particular, you'll be able to do these things with predicate functions

You'll also learn some operations on lists. In particular, you'll be able to:

You'll get more practice with test-driven development: working towards making test cases pass.

Step by Step Instructions

Step 0: Get together with your pair partner.

Please work with the same person you worked with on lab04, unless your TA pairs you with someone else for some reason.

Step 1: Read over the entire lab together

It will really help if you both understand the big picture before moving on.

Step 2: Together with your pair partner, make a posting to the lab05 Gauchospace Pair Partner forum

Just post your names and the times that you can work together.

Step 3: Decide whose account you are going to work in

Note: DO NOT share passwords with each other. That is a violation of your account agreement, and can result in suspension of your computing privileges at UCSB.

Instead, what you should do is:

Step 4: Create a directory for lab05 on one of your accounts.

Create a ~/cs8/lab05" directory. If you've forgotten how, consult lab03.

Step 5: Bring up IDLE, and a window for function definitions

Open IDLE, bring up the New Window, save the file (substituting your own name), and start by putting a header comment at the top, with your names, date, the name of the assignment, and a one line description of what the file is for.

The one line description can be something like

# Test Driven Development of predicate (boolean) functions and list functions.
The file name should be lab05.py

Now proceed with Step 6.

Step 6. Copy my starting point file into your file, and run it

The starting point for this week's lab can be found at this link:

http://www.cs.ucsb.edu/~pconrad/cs8/10F/labs/lab05/code/lab05StartingPoint.py

Learning about Python docstrings

Before you run the file, there is one thing to notice about nearly every function definition in the file—Notice how most of the function definitions have a docstring—an example is shown below. This is an an alternative way to document a function. The advantage of using a docstring is that works together with the built-in "help" function in Python. You can type help(functionName) to get information about functions that use docStrings:

def isList(x):
   """
   indicates whether value of argument is of type list
   isList: any -> boolean

   consumes: an argument of any type
   produces: boolean, True if the argument is of type list, otherwise False
   """
   
   return ( type(x) == list )   # True if the type of x is a list  
  
  

Then, choose Run => Run Module, and see the output.

Before we look at the output in detail, try this—type help(isList) at the Python prompt:

>>> help(isList)
Help on function isList in module __main__:

isList(x)
    indicates whether value of argument is of type list
    isList: any -> boolean
    
    consumes: an argument of any type
    produces: boolean, True if the argument is of type list, otherwise False
>>> 

You'll see the contents of the docstring come out.

The initial output of this week's lab

Now that that's done, take a look at the output you get when you Run the module (F5).

You'll see:

It should look something like this:

>>> ================================ RESTART ================================
>>> 
Running 
test_isList:
   passed: isList([])...
   passed: isList([1])...
   passed: isList([2,3,4])...
   passed: isList(['foo',[2,3,4]])...
   passed: isList(1)...
   passed: isList('12')...
Running 
test_isString:
 FAILED:isString('1')...  check: stub expect: True
 FAILED:isString("foo")...  check: stub expect: True
 FAILED:isString(1)...  check: stub expect: False
 FAILED:isString([1])...  check: stub expect: False
 FAILED:isString(['a','b'])...  check: stub expect: False
=======================================
Failed: 5 tests
>>>   
  
  

So, you might come to the conclusion that this lab is going to be a breeze—fill in one stub, get those give test cases to pass, and you are all done.

Well, not quite so fast. In fact, the file is set up at the moment to only run two of the testFunctions in this file—in fact, there are 13 test functions in this file—and when all of them are run, there are 64 tests that are failing.

To see this, after doing Run => Run Module, try typing allTests() at the Python Shell prompt. You should see output something like this:

>>> allTests()
Calling  test_countEvens
test_countEvens:
 FAILED:countEvens('1')...  check: stub expect: False
 FAILED:countEvens(['a','b'])...  check: stub expect: False
 FAILED:countEvens([])...  check: stub expect: 0
 FAILED:countEvens([1,2,3,4,5])...  check: stub expect: 2
[Many lines of output deleted here to save space]
 FAILED:onlyEvens([2,3,4])...  check: stub expect: [2, 4]
Calling  test_totalLength
test_totalLength:
 FAILED:totalLength('1')...  check: stub expect: False
 FAILED:totalLength(['a','b'])...  check: stub expect: 2
 FAILED:totalLength([])...  check: stub expect: 0
 FAILED:totalLength(['Go','Gauchos'])...  check: stub expect: 9
 FAILED:totalLength(['x','xxx','xxxx'])...  check: stub expect: 8
Failed tests:  64
>>>   
  
  

In all, there are thirteen functions that are being tested when you run the allTests() function.

The table below shows the complete run down of what you must do to complete this lab.

 

Function Name Test sample Call
(of working function)
Brief Explanation
(see function's doc string for more details)
isList go(0,1)
>>> isList([1,2,3,4])
True
>>>      
    
indicates whether value of argument is of type list
isString go(1,2)
>>> isString('x')
True
>>>      
    
indicates whether value of argument is of type str
isAdditivePrimaryColor go(2,3)
>>> isAdditivePrimaryColor('red')
True
>>>      
    
indicates whether argument is one of "red", "green", "blue"
isSimpleNumeric go(3,4)
>>> isSimpleNumeric(5.2)
True
>>>      
    
indicates whether value of argument is either of type int or float
hasNoE go(4,5)
>>> hasNoE("Isla Vista")
True
>>>      
    
Returns True unless the argument is a string with an e in it (upper or lower case)
hasNoX go(5,6)
>>> hasNoX('Fred')
True
>>>      
    
Returns True unless the argument is a string with an x in it (upper or lower case)
isListOfSimpleNumeric go(6,7)
>>> isListOfSimpleNumeric([2,2.5,3])
True
>>>      
    
Returns True if argument is a list, and it contains values of type int and float
isListOfIntegers go(7,8)
>>> isListOfIntegers([2,4,7])
True
>>>      
    
Returns True if argument is a list, and it contains values of type int
isListOfEvenIntegers go(8,9)
>>> isListOfEvenIntegers([2,4,6])
True
>>>      
    
Returns True if argument is a list, and it contains even values of type int
totalLength go(9,10)
>>> totalLength(['Go','Gauchos'])
9
>>>
Returns the combined total length of all strings in a list of strings
lengthOfEach go(10,11)
>>> lengthOfEach(['x','xxx','xxxx'])
True
>>>      
    
Given a list of strings, turns it into a list of integers, where each value is replaced by the length of the corresponding string.
countEvens go(11,12)
>>> isList([1,2,3,4])
True
>>>      
    
 
onlyEvens go(12,13)
>>> isString('x')
True
>>>      
    
 

How to use the go() function to make your job much easier

Find the function call to go() near the bottom of the file. It looks like this:

# @@@ When working on the lab, uncomment the line below
# and change the 0 and 2 to whatever tests
# @@@ you want to focus on.

go(0,2)

As the command explains:

You can also use go() to run all the tests—that uses the default values of the start and end parameters.

How the go() function for this lab works

The go() function uses a hardcoded list of tests called tests—see just above the definition of the go() function. It then uses a for loop to go through each of those tests and run them, one by one.

This has the advantage of being easy to understand—in fact, you can look at the definition of go() and probably understand how it works. The only "trick" is to understand that tests[i]() means to treat tests[i] as a function, and call it.

There's nothing special about the name go()

By the way—in case this wasn't clear before, there is nothing special in Python about the name go(). The go() function in these labs is just a function we write to make things more convenient for you when testing, and your TAs when grading.

We could have called it doMyBidding(), or showAllMyHardWork() or showtime() instead of go(). I picked the word go() because we end up typing this a lot when testing, and its the shortest word I could think of that makes sense in this context. So, basically, its a lazy choice.

As you'll learn In CS16, CS24 and CS56, in C, C++ and Java programming, there is a function called main() that plays a special role in the language—it's the place that a program always starts. In those languages we don't get to pick the name—there always has to be a main(), and the program always starts by calling that function.

In this lab, the go() function is playing a similar role that a main() function would in C/C++/Java, except we get to pick the name ourselves.

allTests()—an alternative to the go() function.

The disadvantage of the go() function is that it depends on the hard coded value in the tests list—when you add a new function, you have to remember to add it in to the tests list manually. The trouble is, you might forget.

There is another way—a way that will automatically go out and look for every function that has a name starting with "test_" and run every single one of those. I've provided an example of that function—its the allTests() function. The inner workings of that function are a bit beyond what we can cover in CS8—but if you would like an extra challenge, you can take a look at it, and see if you can figure out how it works. In a nutshell, it works in a similar way to the go function, except it constructs the tests list automatically.

Ok time to get to work!

Your job is now straightforward—go through every function that is failing its tests, and make them all pass.

 

When you are all done, you should be able to run go() or allTests() and see zero failed tests.

When your file passes all the tests, and you've correctly removed all the comments that have @@@ lines in them (after following the instructions they contain) you are almost finished and ready to submit!

But first, do a visual inspection of your code to make sure it is ready... that's the next step.

Step 7: Final inspection, and submitting on CSIL

Before you submit your assignment, check these things:

When all that is done:

 


Evaluation and Grading Rubric (300 pts)

Points Item
25

Professional software practices:

  • Naming the file lab05.py
  • Having a comment at the top of the file that complies with the instructions.
  • All @@@ comments have been complied with and removed.
  • Submission follows all instructions and is on time.
25 isString passes its tests and is written with good style
25 isSimpleNumeric passes its tests and is written with good style
25 hasNoE passes its tests and is written with good style
25 hasNoX passes its tests and is written with good style
25 isListOfSimpleNumeric passes its tests and is written with good style
25 isListOfIntegers passes its tests and is written with good style
25 isListOfEvenIntegers passes its tests and is written with good style
25 totalLength passes its tests and is written with good style
25 lengthOfEach passes its tests and is written with good style
25 countEvens passes its tests and is written with good style
25 test_onlyEvens passes its tests and is written with good style
???  

 

Due Date: Friday, October 29, 5pm

Will be accepted late, with 60 pt penalty through: Wednesday, November 3, 11:59pm.... after that, a zero will be recorded.

But: you are encouraged to finish it as soon as possible. You don't want this hanging over you over the Halloween weekend, do you? No, I didn't think so.


Copyright 2010, Phillip T. Conrad, CS Dept, UC Santa Barbara. Permission to copy for non-commercial, non-profit, educational purposes granted, provided appropriate credit is given; all other rights reserved.