===OK - one more variation. And, let's fix it! q2_e - def q2_e(l): print "running q2_e(%s)" % (str(l)) index = 0 a = l[index] b = l[index+1] while a != b and index < len(l) - 1: index = index + 1 if a == b: return False else: return True Seems to make sense: while adjacent elements are equal, then keep moving up the list you will stop, if either you get to the end of the list, or, you found two elements that are the same. test that, and return the correct value. But: running q2_e([0, 1, 2, 3, 4]) len(l) is 5, so len(l)-1 is 4 a = 0 b = 1 index = 0 1 2 3 4 True sb True - happens to be right running q2_e([0, 0, 2, 3, 4]) a = 0 b = 0 index = 0 False sb False happens to be right running q2_e([0, 2, 3, 3]) a = 0 b = 2 index = 0 1 2 3 True sb False running q2_e([]) q1_3_almost_fixed: def q2_e_almost_fixed(l): print "running q2_e_almost_fixed(%s)" % (str(l)) index = 0 a = l[index] b = l[index+1] while a != b and index < len(l) - 2: index = index + 1 a = l[index] b = l[index+1] if a == b: return False else: return True The problem is still the empty list or a list with one element Is this right? def q2_e_fixed(l): print "running q2_e_fixed(%s)" % (str(l)) index = 0 while l[index] != l[index+1] and index < len(l) - 2: index = index + 1 if l[index] == l[index+1]: return False else: return True No - you will get an index out of range if there are no duplicates! Remember short circuiting? def q2_e_fixed(l): print "running q2_e_fixed(%s)" % (str(l)) index = 0 while index < len(l) - 2 and l[index] != l[index+1]: index = index + 1 if l[index] == l[index+1]: NOPE - still get an error here return False if 0 or one elements else: return True Here is a fix def q2_e_fixed(l): print "running q2_e_fixed(%s)" % (str(l)) index = 0 while index < len(l) - 2 and l[index] != l[index+1]: index = index + 1 if len(l) < 2: return True else: if l[index] == l[index+1]: return False else: return True ======= formatted printing First, we can use the tab character to lay values out in a column; and \n characters to go to the next line: Shell: print 'one\ttwo\nthree\tfour' Suppose we want to print: x = 54.33333333 st = "hello there bear" x=54.3333333333 and st="hello there bear" i = 4 Let's try it with a plain print: print "x=",x, "and st=", st, "and i=",i the simple print statement always includes a space here's a fancier version: print string with placeholders % (variables filling in the placeholders) placeholders: %d for an int %s for a string %f for a float print "x=%f and st=%s and i=%i" % (x, st,i) Suppose we want just two decimal digits: print "x=%.2f and st=%s and i=%i" % (x, str,i) if you don not want to skip a line, put the comma at the end: print "x=%f and st=%s" % (x, st), print "and i=%d" % (i) ===[madlab1.py] So, here is an interesting use of printing: '''Let's finally clear up the mystery of 'if __name__ == "__main__":' Try running this directly, and also from importer.py. Written by William Fairgrieve''' What I want: Dear Aunt *Sally*, Thank you for the *wonderful* gift. I never had an *elephant* before. I can use it to fix all my *chairs*. Love, your nephew We want the ** words to be parameters. So, let's write it: def thank_you(word0, word1, word2, word3): '''Thank your aunt for the lovely gift.''' print "Dear Aunt %s," % word0 # print "Dear Aunt",word0,"," wouldn't work - you would get the # extra space print "I want to thank you for sending me the %s gift." % word1 if word2[0] in ['a','e','i','o','u']: determiner = 'an' else: determiner = 'a' print "I never had %s %s before. I can use it to fix all my %s." \ % (determiner,word2, word3) print "love, \nYour niece \nxo" if __name__ == "__main__": word0 = raw_input('Name of a person (Female) ') word1 = raw_input('adjective ') word2 = raw_input('noun ') word3 = raw_input('plural noun ') thank_you(word0, word1, word2, word3) ===Modules We know we can import moduels that already exist, like picture or math or sys. what does import do? - causes Python to execute everything in the module - what does it mean to execute a def statement? defines the function. You can use any .py file as a module! you can import it from another file, or from the shell. __name__ is defined for you automatically. it is __main__ if the file is NOT being imported by another one. That's the case we've been seeing. It is the name of the module (the file name, not including the .py) if it IS imported. ==Simple example [importer1.py] import sample x = 5 print "In importer1: my name is",__name__ print "now I'm calling sample.myfun" x = sample.myfun(33) print 'Back in importer1. The returned value is',x def myfun(i): print "I'm inside myfun, inside sample.py" print "__name__ is", __name__ print "I'm about to return a value to the caller" return i * 3 === The import statement executes everything in sample - it has only the fuction definition, so that's all that is performed. add to sample.py print "I'm inside sample. These lines will print, no matter what. In", print "fact, these lines will print when sample is imported. So, these" print "will be the first lines printed!" run it, and trace what is going on. Use two windows, I guess, so you can see what is printed, and also look at the code. == Suppose we don't want sample's main code print statement, WHEN sample is imported; but we DO want sample's main code print statement, WHEN sample is NOT imported... you guessed it! if __name__ == '__main__': print "I'm inside sample. These lines will print, no matter what. In", print "fact, these lines will print when sample is imported. So, these" print "will be the first lines printed!" of course, now what is printed is incorrect - these lines will be printed if sample is called directly, and not imported. They will not print if sample is imported instead. Why? Simple - it's an if-statement. The test is true, only if __name__ is '__main__'. now, call it directly then, call importer1.py which calls it. ==== for another example: importer.py import madlib -- see, no test test, so the main program is executed. then, import madlib1 -- now the test is there, so we just have the call in importer.py ===So, examples of modules? media is a good one maybe you often process files with particular formats. you could have a module that inputs stuff from a file, prints the contents; any program could just import that with one line. import dnaFormat dict = dnaFormat.get_input("earthWorm.dna") # here you could do whatever calculations you want to do with # earthWord DNA data; then print it dict = dnaFormat.pretty_print("earthWorm.dna") another program, might input data from, e.g., "asianElephant", calculate some mutations, then print the results. You wouldn't have to cut and paste get_input and pretty_print and put them in both of your programs -- you can just import them, with one line. === let's do another example, and illustrate something else get in the shell - we can import into the shell too, of course. You knew that, from working with the media module import temperature x = temperature.to_celsium(72) print x print temperature.above_freezing(x) help(to_celsius) Guess what? Include a docstring! then shown in help import temp_with_doc ===math module import math into the shell dir on it call some functions pretty nice! Could help you do your math and science homework... === Note: I won't lie to you. You CAN do this: from math import * from matlib import * then, you don't have to use the module name Show in shell The problem with this is you can make a mistaken. you could have the same function defined in two modules you import. For example, "print_data". so, it is better to import BLAH and explicitly use the name. It is easier to read too, because this will remind someone reading your code where the methods and functions are defined. === Parameters Let's see something cool that Python allows you to do You've seen some examples of this, in the help strings. [default_define.py] def total(values, start=0, end=None): '''Add up the values in a list. If none are given, the total is zero. If 'start' is not specified, start at the beginning. If 'end' is specified, go up to but not including that index; otherwise, go to the end of the list.''' if not values: return 0 if end == None: end = len(values) result = 0 for i in range(start, end): result += values[i] return result Trace through this: total([3,4,5,6,7],end=2) total([3,4,5,6,7],end=2,start=1) total([3,4,5,6,7]) The none default parameters have to come first in the list. But order among the default parameters doesn't matter. ===Another cool thing Python lets you do: let's write a function that finds the max of any number of values [our_max.py] We haven't written this yet. def our_max(*values): '''Find the maximum of any number of values.''' values is a list of any number of values! let's use m - we'll return the maximum value in m initialize it? if you KNOW of a number that is bigger than any that will be in your data, then you can initialize max to that. suppose you KNOW that the data are month numbers def our_max(*values): '''Find the maximum of any number of values.''' if not values: return None # this is guaranteed to be bigger than all the values, assuming # we know these are months m = 13 for v in values: # get them to fill this in if v > m: m = v return m But suppose we do not know of a maxium value. what can we do? if not values: return None m = values[0] for v in values[1:]: if v > m: m = v return m the * tells python to gather up the arguments, and put them in a tuple, and assign that tuple to values. max(4,22,6,44,2,100) values -> 0 1 2 3 4 5 | | | | | | v v v v v v 4 22 6 44 2 100 The * parameter must be the last one on the list ====