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
bool(the name for Boolean in Python)
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.
Please work with the same person you worked with on lab04, unless your TA pairs you with someone else for some reason.
It will really help if you both understand the big picture before moving on.
Just post your names and the times that you can work together.
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:
Create a ~/cs8/lab05" directory. If you've forgotten how, consult lab03.
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
Now proceed with Step 6.
The starting point for this week's lab can be found at this link:
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.
"Gauchos rule!", or
"isList, imma let you finish, but isString is the best function ever!"then type help(isList) again to see that your message comes out in the docstring.
Now that that's done, take a look at the output you get when you Run the module (F5).
isList(all of which are passing)
isString(all of which are failing).
It should look something like this:
>>> ================================ RESTART ================================ >>> Running
test_isList: passed: isList()... passed: isList()... 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()... 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)
(see function's doc string for more details)
>>> isList([1,2,3,4]) True >>>
|indicates whether value of argument is of type list|
>>> isString('x') True >>>
|indicates whether value of argument is of type str|
>>> isAdditivePrimaryColor('red') True >>>
|indicates whether argument is one of "red", "green", "blue"|
>>> isSimpleNumeric(5.2) True >>>
|indicates whether value of argument is either of type int or float|
>>> hasNoE("Isla Vista") True >>>
|Returns True unless the argument is a string with an e in it (upper or lower case)|
>>> hasNoX('Fred') True >>>
|Returns True unless the argument is a string with an x in it (upper or lower case)|
>>> isListOfSimpleNumeric([2,2.5,3]) True >>>
|Returns True if argument is a list, and it contains values of type int and float|
>>> isListOfIntegers([2,4,7]) True >>>
|Returns True if argument is a list, and it contains values of type int|
>>> isListOfEvenIntegers([2,4,6]) True >>>
|Returns True if argument is a list, and it contains even values of type int|
>>> totalLength(['Go','Gauchos']) 9
|Returns the combined total length of all strings in a list of strings|
>>> 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.|
>>> isList([1,2,3,4]) True >>>
>>> 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.
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.
By the way—in case this wasn't clear before, there is nothing special in Python about the name
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
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
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.
First, read the file from top to bottom—including the code that doesn't have @@@ comments.
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.
Before you submit your assignment, check these things:
When all that is done:
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.