Software Design Lecture Notes Fall 2004 For next time: 1) Prepare for the exam on Thursday 2) Finish Homework 4 A Python template ----------------- When I start a new Python program, I start with the following template: import sys def main(script, *args): print script print args if __name__ == '__main__': main(*sys.argv) It's not very much code, but there is a bunch of stuff there that we haven't played with. argv ---- Start by making a file named template.py with the following: import sys print sys.argv Now run the program and give it some command-line arguments: $ python template.py one two three It should print: ['template.py', 'one', 'two', 'three'] argv is a list of strings. __name__ -------- Now add another line that says print __name__ And run the program again. __name__ apparently gets the value __main__ But now run the program again by starting Python and importing it... >>> import template [''] template >>> Now the argument list is empty, and __name__ is template. What this means is that we can use __name__ to tell whether we are executing the file as a script or importing it. So a lot of Python files look like: def this(): def that(): def the_other_thing(): if __name__ == '__main__': # run some test code here # otherwise just define the functions So if you run it as a script, it does something (usually some test code). And if you import it, it just defines things. Example: look at the tail of World.py, and the head of Wanderer.py reimporting ----------- While we are talking about importing, try to import template.py again... >>> import template >>> Nothing! Python keeps track of what has been imported and only does it once. This is a pain if you are working on template.py. If you make a change, you would like to reimport it. To reload a module, use >>> reload(template) [''] template But notice that, annoyingly, import is a statement and reload is a function. Parsing argv ------------ Now change template.py like this: import sys def main(args): print args if __name__ == '__main__': main(sys.argv) And run it again from the command line: $ python template.py one two three ['template.py', 'one', 'two', 'three'] Now inside main, we could assign the arguments to variables. BUT, it often convenient to take advantage of Python parameter-passing. To understand that, let's take a detour... gather ------ If a function takes a variable number of arguments, you can "gather" the arguments with the * operator. Try this in the interpreter: def foo(*args): print args foo(1) foo(1, 2) foo(1, 2, 3) You can also combine required and optional parameters: def bar(required, optional='default', *the_rest): print required print optional print the_rest bar(1) bar(1, 2) bar(1, 2, 3) bar(1, 2, 3, 4) scatter ------- If you pass a sequence as an argument, it gets assigned to a single variable. def baz(a, b, c): print a, b, c t = (1, 2, 3) baz(t) Oops! Now try this: baz(*t) Yeah! Strangely, the * operator works in the context of an argument list (scatter) or a parameter list (gather). The template ------------ And that brings us back to the template: import sys def main(script, *args): print script print args if __name__ == '__main__': main(*sys.argv) Now we know how it works... $ python template.py one two three template.py ('one', 'two', 'three') In other cases, we want to parse additional arguments. if __name__ == '__main__': main(*sys.argv) # scatter the command-line args def main(script, filter='is_palindrome', *args): # peel off the script name # assign the first argument to filter # gather the rest file='/usr/share/dict/words' apply_filter(file, filter, *args) # scatter the rest def apply_filter(file, filter, *args): # assign the two required parameters and gather the rest