Software Design Spring 2007 For today you should have: 1) read Chapter 16 2) started Homework 7 For Monday you should: 1) work on Homework 7 2) read your emergency auxiliary backup book 3) prepare for a quiz Optional parameters ------------------- When you define a function, you can provide default values for the parameters: class Point: def __init__(self, x=0, y=0): self.x = x self.y = y Then when you call the function, you can optionally override the defaults: p1 = Point() # creates the point (0,0) p2 = Point(5) # overrides x but not y p3 = Point(5, 7) # overrides x and y In the previous three examples, the arguments are positional; they get assigned to the parameters in order. You can also provide keyword arguments that include the name of the parameter: p4 = Point(y=7) # overrides y but not x If you have positional arguments and keyword arguments, the positional arguments have to come first. p5 = Point(5, y=7) # good p6 = Point(y=7, 5) # bad Quiz 4 solution --------------- "the cutest quiz ever" class Kangaroo: def __init__(self): self.pouch_contents = [] def put_in_pouch(self, obj): self.pouch_contents.append(obj) kanga = Kangaroo() # remember lower case for variable names, roo = Kangaroo() # upper case for classes. kanga.put_in_pouch(roo) Several of you gave __init__ an optional argument: def __init__(self, contents=[]): # CAREFUL!!! self.pouch_contents = contents As it turns out, it is very dangerous to use a mutable object as a default value. The default values are only evaluated once, when the function is defined. Thus, all Kangaroos (that don't override the default) get a reference to the same (initially) empty list. If you add something to any pouch, all Kangaroos see the change! MUTABLE OBJECTS + ALIASING = IMPENETRABLE BUGS Survey results -------------- 1) Time on homeworks is 3-9 with a mode of 6 hours. A few people over 12 hours per week, many under. If you started the project early, you should be working on it. Otherwise, you should be looking for projects. I will pass out the "call for proposals" next week. Time on reading is about right. We're done with the book! 2) First exam: a few thought it was too hard, but most thought it was too long. 3) The distribution of answers to "comfort" and "pace" are about right. 4) The answers to "how did your preparation compare" were interesting. In theory, the distribution of answers should be uniform. Actual answers were remarkably uniform _except_ that 8/33 = 24% of you think you were in the top 10%. That suggests that some of you are underestimating your classmates. 5) Answers to the "serves the needs" questions were mostly positive. Several people wrote something like, "ok for me, but maybe not as good for X". But then some of the Xs wrote "ok for me, but maybe not for Y". Suggestions: More object-oriented design principles. Periodic big-picture review. Supplemental readings. Resources for learning about advanced material. Evaluation other than programming on paper. Hard to get help without getting answers. Replace JFFEs with more open-ended problems ("JFFEs are semi-required") More ideas for extensions to homeworks. More programming assignments, more JFFEs. Opportunities to show off cool programs. Solution code on web page. Option to start project sooner. Deeper look into each topic. Harder homeworks. Multiple sections? Stack diagrams? Extra warmups. Go over book exercises in lab? Need to learn C and C++. Classroom atmosphere could be more newbie-friendly. Periodic big-picture review --------------------------- What we have done so far: 1) functional interface design 2) data structure selection/design 3) basics of object-oriented programming 4) some algorithmic design patterns (search, DSU) What's coming up: 1) object-oriented design 2) graphical user interfaces 3) multi-threaded programs 4) network programming / remote objects 5) 3D graphics These modules are mostly random-access, so if you know you need one for your project, let me know and I will provide pointers. try...except ------------ Structurally similar to if...else. try: d[key] += 1 except: d[key] = 1 The try clause can contain multiple statements. If an exception (run-time error) occurs, the try clause is aborted and the except clause is executed. If the try clause executes without an exception, the except clause is skipped. DANGER: if you use a try statement to handle an particular, expected error, be careful not to "smother" an unexpected error. Partial solution: specify the type of exception to catch. try: d[key] += 1 except KeyError: d[key] = 1 How do you learn the names of the exceptions? Handling unusual conditions --------------------------- We have now seen three ways of dealing with unusual conditions (discussion based on the Python Cookbook, Alex Martelli) LBYL (look before you leap): if key in d: d[key] += 1 else: d[key] = 1 EAFTP (easier to ask forgiveness than permission): try: d[key] += 1 except KeyError: d[key] = 1 HDC (homogenize different cases): d[key] = d.get(key, 0) + 1 What are the pros and cons? Homework 5 solutions -------------------- http://wb/sd/solutions/randomtext.py 1) for the buffer and the keys in the dictionary I used tuples of words def process_word(word, order=2): """process each word. During the first few iterations, all we do is store up the words; after that we start adding entries to the dictionary.""" global prefix if len(prefix) < order: prefix += (word,) return try: dict[prefix].append(word) except KeyError: # if there is no entry for this prefix, make one dict[prefix] = [word] prefix = shift(prefix, word) def shift(t, word): """form a new tuple by removing the head and adding word to the tail""" return t[1:] + (word,) 2) the values in the dictionary are lists of strings def random_text(n=100): """generate n random words, starting with a random prefix from the dictionary""" # choose a random prefix prefix = random.choice(dict.keys()) for i in range(n): suffixes = dict.get(prefix, None) if suffixes == None: # if the prefix isn't in dict, we got to the end of the # original text, so we have to start again. random_text(n-i) return # choose a random suffix word = random.choice(suffixes) print word, prefix = shift(prefix, word) 3) random_text demonstrates a slightly unusual use of recursion