Lab 10 - Changing Arguments & Recursion


Directions for Labs


  • Submit your completed lab file online to CourSys (not Canvas). Labs are marked on completion, not correctness, so complete each part to the best of your ability and learn!
  • It is recommended that students attend in-person lab sections for lots of help!
    • If you would like to attend an in-person lab section, you are welcome to come to any (or more than one) lab section.
    • There is no need to attend the section you are enrolled in.
    • There is no need to attend any lab sections: there is no attendance taken.
    • You can complete the lab on your own time or own computer if you like.
  • While completing these labs, you are encouraged to help your classmates and receive as much help as you like. Assignments, however, are individual work and you must not work with another person on assignments.


Part 1) Changing Arguments


  1. Inside your cmpt120 folder, create a new folder for lab10 and make a lab10.py file.
  2. Create a function named change_number(...) which accepts one parameter: a number.
    • The function only needs one line: add 1 to the function's parameter.
    • Example:
      def change_number(num):
          num = num + 1
  3. Add the following code to the main part of your program, but don't run it yet!
        num_oranges = 3
        change_number(num_oranges)
        print("Num Oranges: ", num_oranges)
    • First predict what the program will print.
    • Next, run the program and test it. Think about if it met your expectations.
  4. Change your main code to set num_oranges to be a floating point number.
    • First predict what the program will print.
    • Next, run the program and test it. Think about if it met your expectations.
  5. Create a function named change_list(...) which accepts one parameter (a list).
    • Make the function add one to the first element of the list, such as:
      my_list[0] += 1
    • In the main code, create a new list variable of three numbers (such as ages = [11, 12, 13]). Pass it to the function then print that list in main.
    • First predict what the program will print.
    • Next, run the program and test it. Think about if it met your expectations.
  6. Create a new function named change_string(...) which appends an a to the end of its string parameter.
    • As before, create a string variable in main, pass it to the function, then have main print its value.
    • First predict what the program will print.
    • Next, run the program and test it. Think about if it met your expectations.
  7. Repeat this test for a dictionary. Set the dictionary to have a key "apple". Have the function change this key's value, along with adding a new key-value pair.
    • Call from main as above.
    • First predict what the program will print.
    • Next, run the program and test it. Think about if it met your expectations.
  8. In your lab add a comment about which variables in the main code have their values changed by the functions.
  9. In main, create a list of three integers and then pass the first element to the change_number(...) function such as:
    change_number(my_list[0])
    • Print the list to see its final value in main.
    • First predict what the program will print.
    • Next, run the program and test it. Think about if it met your expectations.
    • Add a comment mentioning the difference between passing a list-of-integers to a function, and passing an element of the list.
  10. Repeat the test for change_list(...), but this time pass in a copy:
    • In main, create a new list of three numbers.
    • Pass a copy of the list into the function, such as one of the following three ways:
      change_list(my_list[:]) or
      change_list(my_list.copy()) or
      change_list(list(my_list))
    • Print the list in main and predict if it will change. Run it!
    • Add a comment describing your findings.
  11. Move all your code from the main section into its own function called part1_passing_to_functions() so your code is ready for part 2!


Part 2) Recursive Line


  1. Add a Turtle to your program:
    • Importing the package
    • Creating a turtle (I named mine monet).
    • Set the turtle's speed to something slow (1 is good to start).
    • Add the exitonclick() call at the end as usual.
  2. Create a new function named draw_row(n):
    • The function will be recursive.
    • For the base case fo n == 0, have it write the text "0 - Done row".
    • Hint - write: You can write text to the screen with: monet.write("0 - Done row").
    • For the recursive step, have it draw a row like the following (for n==3):
      One line for n=3
    • Detailed steps (if needed; OK to try without following these):
      1. Point right:
        Put the pen down and set the heading to 0 (point to the right).
      2. Display n:
        Write to the screen the value of n.
      3. Draw a bar:
        Move forward 50 and then stamp.
      4. Recursive step:
        Recursively call draw_row() with argument n-1
      5. Move back to where this call started from:
        Put the pen up, and the move backward 50.
  3. From main code, call your function passing in an argument 3.
    • Run the program.
  4. Test your program with other values of n between 0 and about 6.
  5. Troubleshooting (as needed):
    • There is no loop in this code. It is recursive because it calls itself.
    • Ensure your recursive function has a base case (n == 0 in this case) which does not call itself.
    • Ensure that other cases call itself but break the problem down a little by passing in n - 1.
    • Debug with:
      • n=0:
        One line for n=0
      • n=1:
        One line for n=1
      • n=6:
        One line for n=6
    • Try stepping through your program with the debugger if it's not working.
    • The full code is available near the end of this lab if you are absolutely stuck!


Part 3) Draw Tower


  1. Create a new recursive function named draw_tower(...)
    • Pass in argument rows to represent how many rows the tower should have.
    • If rows=3 then draw three rows using the above draw_row(n) function. Bottom row would be length 3, then next row up is length 2, then length 1.
    • Move up and down:
      • Move up 50 for each row.
      • When done the row, move back down 50 so that when done drawing the tower the turtle is back to the start.
    • At the very top, print "Done Tower".
    • Your tower should look like:
      Tower for rows=6
    • Try implementing this function on your own if you can! Here are some hints to walk you through it.
    • Hint - Recursion: Recursion will be on the argument rows. Base case is rows == 0, each recursive call executes draw_tower(rows - 1).
    • Hint - Base Case: For the base case (rows == 0), move up 50, write the "Done Tower" text, and then move back down 50.
    • Hint - Recursive Step: For the recursive step (rows != 0) move up, call draw_row(rows), then make the recursive call draw_tower(rows - 1). Finally, move back down to reset the turtle to where it was when the function started.
    • Hint - Move Up/Down: To move up, set the turtle's heading to up (monet.setheading(90)) and move forward 50. Ensure the pen is up or down as needed. To move down, set heading to 90 and move backward 50.
  2. Call it from your main program:
    draw_tower(6).
  3. Troubleshooting Ideas:
    • Set the turtle speed to 1, and then watch it run. See where it goes wrong.
    • Call draw_tower(0) and prove it draws the text OK:
      Tower rows == 0
    • Call draw_tower(1) and see if its behaviour meets expectations:
      Tower rows == 1
    • The full code is available near the end of this lab if you are absolutely stuck!

Part 4) Optional Challenges


  1. [Optional] Try using recursion to draw n boxes all with their lower left corner at (0,0), each one bigger than the next one.
    • Idea: Plan out your base case and recursive step first.
  2. [Optional] Try using recursion to draw n boxes all centered at (0,0), each one bigger than the next one.
    • Idea: Plan out your base case and recursive step first.
  3. [Optional] Try using recursion to a series of n triangles, each with their lower left at (0,0).
    • Idea: Plan out your base case and recursive step first.
  4. [Optional] Create an algorithm that makes it look like the view is looking straight down a long train tunnel.
    • Idea: The boxes of the tunnel that are nearest the viewer will be further apart compared to ones in the very distance.

Full Code


If you need it, here is the full recursive code.

Please only use after you have really tried to write the code yourself with the above hints!

  • Hint - Full code for row
    def draw_row(n):
        if n == 0:
            monet.write("0 - Done row")
        else:
            monet.pendown()
            monet.setheading(0)
            monet.write(str(n))
            monet.forward(50)
            monet.stamp()
            draw_row(n - 1)    
            monet.penup()
            monet.backward(50)
    
  • Hint - Full code for tower
    def draw_tower(rows):
        monet.penup()
        if rows == 0:
            monet.setheading(90)
            monet.forward(50)
            monet.write("Done Tower")
            monet.backward(50)
        else:
            monet.setheading(90)
            monet.forward(50)
            draw_row(rows)
            draw_tower(rows - 1)
            monet.setheading(90)
            monet.backward(50)
    


Submission


Uncomment all your code before submitting.

Submit your lab10.py file to CourSys by Sunday midnight. Remember you can submit up to 3 days late with no penalty if needed (but please plan to get it done on time to stay up to date on the course!)

Topics Covered

  • Experiment with changing an argument's value in a function.
    • Identify when the value in the calling code changes.
    • Identify when the value in the calling code does not change.
  • Experiment with recursion graphically.