text: Note 1: please send all e-mail regarding this class to bc@zesty.ca. Don't use my personal address. This will help me keep all the mail sorted. I get way too much junk mail, so if you send mail to my personal address it may get overlooked.
  Note 2:
  you should view this page in a browser that supports CSS, if you can.
  In the lab,
  i believe the only such browser is Mozilla (run
  mozilla).
  Welcome to Explore 2. I know that doesn't make any grammatical sense, but what else can i call it? I considered "exploration" but that is long and stupid-sounding (like "meditation 2" – ha! sounds like it oughta be the title of a work of classical music or some incomprehensible modern art piece).
  Sorry. Okay, back to Python (the persons responsible for the paragraph above this one have just been sacked).
  1. Functions
  Functions are the big topic of the day. They should be quite familiar to you from other programming languages. Python's function definitions are pretty straightforward; it should be easy to see what this one does, for example.
  >>> def answer_phone(): ... print 'Hello, may I take your order? ... >>>
  The nice thing about functions is that they let you teach the computer how to do something, and then you can ask the computer to do that thing as many times as you like.
  >>> answer_phone() Hello, may I take your order? >>> answer_phone() Hello, may I take your order? >>>
  Functions can take parameters, to specialize what they do. For instance:
  >>> def answer_phone(big_cheese): ... print 'Hello, ' + big_cheese + "'s pizza." ... print 'May I take your order?' ... >>> answer_phone('Tony') Hello, Tony's pizza. May I take your order? >>> answer_phone('Domino') Hello, Domino's pizza. May I take your order? >>> answer_phone('Guido') Hello, Guido's pizza. May I take your order? >>>
  The function body must be indented all to a consistent depth (usually four spaces). If the indentation changes randomly in the middle of a block, you'll get a syntax error (the message will talk about an "indentation error", actually).
  Notice that you need to write the parentheses in the definition even if the function has no parameters. You must also write the parentheses when you call a function. Whenever you use parentheses for this purpose, never leave a space between the function name and the left parenthesis. (This stylistic rule visually distinguishes function calls from parentheses used for grouping in expressions, and thereby makes your code easier to read.)
  Q1.
  What happens if you just type in
  answer_phone
  without the parentheses? What do you think that means?
  Q2.
  Write a function called
  compare
  that accepts two parameters
  and prints a message explaining
  which parameter is bigger or if they are the same.
  For example, compare(3, 5)
  should print a message like
  3 is smaller than 5.
  2. Docstrings
  Try
  help(answer_phone).
  Documentation strings, or "docstrings" for short, explain what your functions do. Just about every function you write should have a docstring, except perhaps for functions that are so simple that their purpose is obvious from the function's name.
  To write one, just put a string right at the beginning of the function body. By convention, docstrings are always written with three double-quote marks at the beginning and the end. The triple-quotes let them easily extend over several lines. Another convention is that docstrings usually start with a succinct, one-line summary; after that they can explain stuff in more detail if necessary.
  >>> def mock(): ... """Mock the user mercilessly. ... ... Print out a well-known insult from "Monty Python ... and the Holy Grail". ... """ ... print 'Your mother was a hamster,' ... print 'and your father smelt of elderberries!' ... >>>
  Many functions are fine with just a one-line description, if the description is written well. (The above example would probably be better off with just a single line.)
  The description should be an imperative sentence stating what the function will do. The one above doesn't say "This function mocks the user" or "Mocks the user mercilessly". It just says "Mock the user".
  Add a documentation string to the
  answer_phone function
  and try asking for help again.
  Q3.
  Add a docstring to your
  compare function.
  It is very important to choose good names for your functions.
  A well-chosen name is short and clear,
  and makes the function's purpose obvious.
  Function names should usually be verbs
  (as in
  answer_phone,
  not
  phone_answerer).
  A common exception to the convention of using verbs
  are functions whose primary purpose is to convert something
  (like
  int) or to extract a property of something
  (like
  len).
  But if a function has an effect
  (it modifies something, writes output, etc.),
  it should definitely have a verb as a name.
  It's also important to choose good names for your variables, especially the function parameters. Variable names should be nouns. Ideally, someone should be able to tell what a function is for, why they would want to use it, and what arguments to pass in, just from the name of the function and names of its parameters.
  3. Return Values
  To return a value from a function,
  just say
  return followed by what you want to return.
  You can combine function calls in expressions in the normal way;
  each function evaluates to the value you return.
  >>> def square(x): ... return x * x ... >>> square(5) 25 >>> square(5) + square(8) 89 >>> square(square(square(7))) 5764801 >>>
  A
  return statement has the effect
  that it ends the function immediately.
  You can also use
  return by itself
  to exit out of a function without returning anything.
  Q4.
  What about functions that don't contain
  return statements?
  What do they evaluate to?
  4. Local and Global Variables
  Variables defined at the top level, outside of functions, are global. Inside a function, you can have a set of local variables that are separate from the global ones.
  Try this:
  def test(): y = 2 print x print y x = 1 print x print y test() print x print y
  Q5.
  What happened?
  What's different about the variables
  x and
  y
  in this example?
  Now try this:
  x = 9 def test(): print x test() print x
  and compare that to this:
  x = 9 def test(): print x x = 1 test() print x
  Q6.
  What happened?
  How did Python decide to treat
  x differently
  in the last two examples?
  It's totally important that you get this. If you are uncertain what is happening here, read the hint.
  To force a variable to be treated as a global, you can use the
  global keyword. Try this:
  x = 9 def test(): global x print x x = 1 test() print x
  When you get here, stand up, stretch, maybe walk around the room. Just get out of your chair for a moment.
  5. Nested Functions
  You can define functions within other functions, if you want. Each new level gets its own set of local variables.
  Here is a classic example:
  def make_adder(x): def adder(y): return x + y return adder
  Q7.
  What does the
  make_adder function do?
  Try these, and make sure you understand the results:
  make_adder make_adder(3) addthree = make_adder(3) addthree(5) make_adder('sid')('ney')
  Consider this function:
  def t(f): def g(x): return f(f(f(x))) return g
  Q8.
  Describe what
  t does.
  What does
  t(square)(7) return?
  Figure out the answer before you try it.
  Maybe you've never seen a language that could do anything like this before. If this is all totally weird to you, call me over and i'll try to explain.
  6. Comparisons
  Any object can be compared
  (using
  <,
  >, etc.)
  with any other object in Python.
  Even two objects of different types can be compared.
  Try
  compare(3, '3').
  (If the output looks silly,
  put one of your shoes on top of your monitor.
  Then fix your
  compare function.)
  Try these:
  compare(3, '5') compare(3, '1') compare(3, '') compare(1, 1.0) compare(1, 0.5) compare(1, 1.1) compare(10/3, 3.3333333333333335) compare(10/3.0, 3.3333333333333335)
  Q9. How does Python compare numbers and strings?
  7. Formatting
  You can also use the
  % operator on strings.
  When the first operand to
  % is a string,
  the string is considered a formatting template and
  the second operand is the value to put into the string.
  Formatting templates are like normal strings except that the '%' character is special. For example, if you write '%d' then an integer value is inserted. Here are the most commonly used codes:
  %d decimal integer is inserted %f floating-point number is inserted %s string is inserted %r repr() of the value is inserted %x hexadecimal integer is inserted
  You can also specify a width (in characters) immediately after the '%'. If the width is positive, the value is right-justified, and any extra space is filled with spaces. If the width is negative, the value is left-justified. For a numerical format, if the width begins with a zero, the padding is filled with zeroes. For a floating-point number, you can specify the precision as well: put a dot after the width, then the number of decimal places.
  Try:
  '%d' % 5 '%10d' % 5 '%-10d' % 5 '%f' % 5 '%.1f' % 5 '%9.2f' % 5 '%s' % 'hello' '%40s' % 'hello' '%-40s' % 'hello'
  You can also specify more than one value:
  >>> 'I went to the %s to buy %d eggs and %d cans of spam.' % ('store', 5, 7) 'I went to the store to buy 5 eggs and 7 cans of spam.' >>>
  In this last case, the second operand to
  %
  is what's called a tuple (an array) containing three values.
  We'll talk more about tuples later.
  This operator can be pretty convenient in
  8. Modules
  Try this:
  >>> import time >>> time.asctime() 'Wed Jan 29 02:30:44 2003' >>>
  You just loaded a module called
  time
  that provided a bunch of other functions.
  One of the functions in the
  time module
  is called
  asctime().
  When you load a module using the
  import statement,
  it is like making an assignment to the name you've imported.
  The variable
  time now refers to the
  time module. Try printing out
  time,
  or asking for the
  type() of
  time.
  Each module has its own namespace (its own set of variable names associated with values). You can access the module's contents using the module name followed by a dot and the name of something inside the module. (This is a lot like Java, if you're familiar with that.)
  To see what else is in the module, try
  dir(time).
  You can use
  dir() on just about any object.
  It will tell you what names are in the object's namespace –
  that is, what you can put after the dot.
  (You will see a lot of entries that start with double-underscores;
  they are special. Don't worry about those for now.)
  dir() with no arguments shows you
  the names in the namespace you're currently in. Try that too.
  Any ordinary Python file can be a module.
  Try putting this in a file called
  counter.py:
  print "Hello!" x = 0 def count(): global x x = x + 1 print x
  Now as long as you're running Python in the directory
  where you saved this file, you can
  import counter
  and call
  counter.count() or look at the value of
  counter.x.
  Notice that when you import a module, all the code in the module runs normally. So, for example, importing this module prints Hello! to the screen. After the module finishes executing, it leaves its namespace around so you can use whatever useful things are in it.
  It is usually bad form for a module to cause effects upon importing, like this one does. You should write modules so that importing them defines things for later use, but doesn't actually take actions. Initialization work is okay, as long as it's quick. Anything more involved should be in a function; the person using the module can call that function when they're ready.
  Python comes with tons of modules.
  Remember the module index?
  You can run
  help() and type
  modules to get a list of all the modules.
  The standard library is filled with wholesome Python goodness!
  9. Sequences
  Have a closer look at the thing returned by
  dir().
  >>> import math >>> dir(math) ['__doc__', '__file__', '__name__', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'cosh', 'e', 'exp', 'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log', 'log10', 'modf', 'pi', 'pow', 'sin', 'sinh', 'sqrt', 'tan', 'tanh'] >>>
  This is a list of strings.
  A list is one kind of sequence.
  A string is also a kind of sequence.
  len() works on both.
  To get a single element out of a sequence,
  you use square brackets surrounding a number
  (an index into the sequence).
  Index numbers start at zero;
  the index number for the last item in a sequence
  is the length of the sequence minus 1.
  If the index number is negative,
  it counts backwards from the end of the sequence.
  So another way to get the last item of a sequence named
  x
  is to say
  x[-1].
  Instead of getting a single item, you can also cut a subsequence out of a sequence. This is called slicing a sequence, and you do this by putting two numbers in the square brackets, separated by a colon. If you put the colon but leave off the number before or after the colon, the slice will extend to the beginning or end of the sequence.
  >>> x = dir(math) >>> len(x) 28 >>> x[8] 'cos' >>> x[:8] ['__doc__', '__file__', '__name__', 'acos', 'asin', 'atan', 'atan2', 'ceil'] >>> x[-5] 'sin' >>> x[-5:] ['sin', 'sinh', 'sqrt', 'tan', 'tanh'] >>> x[10:13] ['e', 'exp', 'fabs'] >>>>> y[8] 'g' >>> y[:8] 'prestidi' >>> y[-5] 'a' >>> y[-5:] 'ation' >>> y[10:13] 'tat' >>>
  Notice that the result of slicing
  y[10:13]
  begins with
  y[10] and ends with
  y[12].
  To keep this straight,
  just remember the rule that
  x[a:b] has the length
  b - a.
  Q10. How do you get "git" out of "prestidigitation"?
  Q11. What happens if you index a sequence using a number that's too big?
  Q12. What happens if you slice a sequence using a number that's too big?
  Q13. How about when you slice a sequence and the starting index is bigger than the ending index?
  You can add lists together (try it) and multiply lists by numbers, too.
  The way to gather things in a list is to start with an empty list:
  >>> froofroo = [] >>> froofroo [] >>>
  and then call the
  append() method to append things to the list:
  >>> froofroo.append(3) >>> froofroo.append(5) >>> froofroo [3, 5] >>>
  We'll talk more about methods later, but for now,
  think of it as a function attached to the list.
  It's a lot like a function within a module
  (and that's why you write it the same way),
  except that the function affects this specific list:
  if you had other lists, of course,
  calling their
  append() methods would affect each of them.
  All right! Onward to the second assignment.
  If you have any questions about these exercises or the
  assignment, feel free to send me e-mail at
  bc
  zesty
  ca.