Name: _K_E_Y____________ Student ID: __________________
1. An orchard grows five apple varieties:
Fuji, Gala, Spartan, Rome, and Melba.
The apples I like are Fuji, Gala, and Rome; let this set be denoted by myFav.
Let yrFav be the set containing Fuji and Melba.
1. Consider the union of myFav and yrFav. Express in words the interpretation of this union in the context of apple preferences. 
The union of myFav and yrFav is the set of apple varieties that eitheryou like orI like.
2. Consider the intersection of myFav and yrFav. Express in words the interpretation of this intersection in the context of apple preferences. 
The intersection of myFav and yrFav is the set of apple varieties that both you and I like.
3. We wish to implement some set operations using bitsets in Python. Define five Python variables Fuji, Gala, Spartan, Rome, Melba with appropriate integer values for use in a bitset. 
```fuji = 1 << 0
gala = 1 << 1
spartan = 1 << 2
rome = 1 << 3
melba = 1 << 4
```
4. Using the variables you just defined, define a Python bitset for myFav. 
```myFav = fuji | gala | rome
```
5. Define a Python function likesGala() that returns a boolean value indicating whether a given bitset includes Gala. Include a short docstring. 
```def likesGala(fav):
"""Returns whether the bitset 'fav' includes Gala."""
return (fav & gala) == gala
```
2. One of the nice things a Python list can do that a C array can't is delete elements from the middle of the list. C arrays have fixed length: so in C array semantics, deleting element 1 from the array [0, 1, 2, 3, 4] results in [0, 2, 3, 4, 4] -- where the last element is just considered junk to be ignored.
1. Write a Python function that takes a list and an index, and deletes the corresponding element from the list. (This function can be nearly trivial in Python.) Include a short docstring. 
```def list_del(thelist, idx):
"""Delete the idx-th element from thelist (modifies thelist)."""
del thelist[idx]
```
2. Write a Python function to do the same, but using C array semantics: don't use Python's ability to delete or take list slices. Include a short docstring. 
```def array_del(thearray, idx):
"""Delete the idx-th element from thearray, using C array semantics."""
for i in range(idx+1, len(thearray)):
thearray[i-1] = thearray[i]
```
3. In your own words, contrast the procedural vs. object-oriented programming paradigms. 
Procedural programming is action-oriented: the code is a sequence of procedures, and the data structures are passed as parameters to the procedures. The focus is on the 'verbs'. In contrast, object-oriented programming is data-oriented: code is organized into classes, centred around objects, and the procedures are treated as methods within each class. The focus is on the 'nouns'.
4. Define or describe each of the following object-oriented terms: 
1. Message: communication between objects; how methods are called
2. Interface: a set of messages that an object can receive
3. Class: a user-defined container type
4. Instance: an object; instances are to classes as variables are to types
5. Attribute: a variable or method belonging to an object
6. Method: a function/procedure belonging to an object
7. Constructor: the special method which is called when an object is instantiated
8. Overloading: giving multiple definitions to a function/method/operator depending on the type of its parameters/operands
5. Given the following block of Python code, consider the names visible to the print statment at the end. For each of the 9 expressions in the print statement, write what would be printed, or if the name is not visible, write 'NameError'. 
```w = 1
class C:
w = 2
x = 3
def __init__(self):
from math import sqrt
w = 4
x = 5
y = 6
self.z = 7
a = C()
w=1, x=NameError, y=NameError, z=NameError,
a.w=2, a.x=3, a.y=NameError (really AttributeError), a.z=7,
sqrt(4.0)=NameError
```
6. Using exceptions, modify the following block of Python code to print, "Can't divide by zero; goodbye!" and exit the loop when the user inputs 0. 
```
try:

while True:

in = input("Type a number and I'll invert it! ")

recip = 1.0/in

print "The reciprocal is:", recip

except ZeroDivisionError:
print "Can't divide by zero; goodbye!"

```
7. The Python text ch10 describes an example application using dictionaries to implement "sparse matrices" -- where only the non-zero entries of a matrix are stored. The keys are (row,col) tuples, and the values are the corresponding non-zero entries of the matrix. For example, a 2x2 sparse matrix with the value 5 in entry (1,0) and the value 3 in entry (1,1) would be represented by the dictionary {(1,0): 5, (1,1): 3}.
1. Write a Python function that returns the number of non-zero entries in a sparse matrix. (Hint: it should be a very short function!) Include a short docstring. 
```def count_nonzero(matrix):
"""Count the number of non-zero entries in a sparse matrix.
Assumes that only non-zero entries are represented in the
dictionary."""
return len(matrix)
```
2. Write a Python function that returns a nicely formatted string representation of a sparse matrix. The function should not print anything, just return a string, akin to the __str__() method. For example, the 2x2 matrix mentioned above might be formatted as, " 0 0 \n 5 3" (but don't worry excessively about the spacing). You may assume the caller will pass in two additional parameters, nrows and ncols, specifying the number of rows and columns in the matrix. Include a short docstring. 
```def __str__(matrix, nrows, ncols):
"""Return pretty-printed string representation of sparse matrix."""
s = ''
for r in range(nrows):
for c in range(ncols):
s += ' %2d' % matrix.get((r,c), 0)
s += '\n'
return s
```