YCL Session 4 Lesson Plan Summary In this session, students will learn about functions, including the parts that make up a function, how to define and call a function, and how to use variables and expression to build custom drawing functions. Using three code snippets and their Session 2 drawing, they will rework their drawing to use functions. Session Goals! Step through the 3 component of a function: defining, calling, using expressions! Understand related concepts such as capturing values and variable scope! Rework drawing example using functions and expressions Agenda! Concepts: Drawing with Functions (15 min) Code Snippet: grass.py Code Snippet: tree.py Code Snippet: forest.py! Activity: Drawing with Functions (45 min) Instructions Concepts: Drawing with Functions (15 min) The goal of this chapter is to learn how to create our own functions to draw. We don t want to be stuck with just draw_circle commands. We want to be able to define create our own draw_tree or draw_house commands. A function is a block of code that we can call with just one line. Functions give us the ability to write: Clear, easy-to-read code. The ability to reuse code. We have already used functions in week 2. Now we want define our own. Defining a function is like giving a recipe to computer. Once we give the computer a recipe for banana bread, we just have to tell the computer to make banana bread. There s no need to tell it the steps again.
To create our own drawing functions we need three things, most of which which we learned last week: 1. How to define a function 2. How to use variables 3. How to create simple mathematical expressions How to Define a Function Defining a function is rather easy. Start with the keyword def, which is short for define. Next, give the function a name. There are rules for function names, which you might remember from last week. They must: Start with a lowercase letter. After the first letter, only use letters, numbers, and underscores. Spaces are not allowed. Use underscores instead. While upper-case letters can be used, function names are normally all lower-case. After that, we have a set of parenthesis. Inside the parenthesis will go parameters. We ll explain those in a bit. Next, a colon. Everything that is part of the function will be indented four spaces. Usually we start a function with a multi-line comment that explains what the function does.
Here is an example of a function: def draw_grass(): This function draws the grass. arcade.draw_lrtb_rectangle_filled(0, 800, 200, 0, arcade.color.bitter_lime) Calling a Function To call the function, all we need to do is: draw_grass() Below is a full program that defines and uses the function. Notice that function definitions go below the import statements, and above the rest of the program. While you can put them somewhere else, you shouldn t. Code Snippet: grass.py This is a sample program to show how to draw using functions import arcade def draw_grass(): This function draws the grass. arcade.draw_lrtb_rectangle_filled(0, 800, 200, 0, arcade.color.bitter_lime) arcade.open_window(800, 600, "Drawing with Functions") arcade.set_background_color(arcade.color.air_superiority_blue) arcade.start_render() # Call our function to draw the grass draw_grass() arcade.finish_render() arcade.run()
Great! Let s make this scene a little better. I ve created another function called draw_pine_tree which will...you guessed it. Draw a pine tree. Here s what that looks like: And here s what the code looks like: Code Snippet: tree.py This is a sample program to show how to draw using functions import arcade def draw_grass(): This function draws the grass. arcade.draw_lrtb_rectangle_filled(0, 800, 200, 0, arcade.color.bitter_lime) def draw_pine_tree():
This function draws a pine tree. # Draw the trunk arcade.draw_rectangle_filled(100, 200, 30, 80, arcade.color.brown) # Draw three levels of triangles arcade.draw_triangle_filled(50, 215, 150, 215, 100, 320, arcade.color.forest_green) arcade.draw_triangle_filled(50, 255, 150, 255, 100, 360, arcade.color.forest_green) arcade.draw_triangle_filled(60, 295, 140, 295, 100, 400, arcade.color.forest_green) arcade.open_window(800, 600, "Drawing with Functions") arcade.set_background_color(arcade.color.air_superiority_blue) arcade.start_render() # Draw our pretty landscape draw_grass() draw_pine_tree() arcade.finish_render() arcade.run() Great! But what if I want a forest? I want lots of trees? Do I create a function for every tree? That s no fun. How can I create a function that allows me to say where I want the tree? Like what if I wanted to draw three trees and specify (x, y) coordinates of those trees: draw_pine_tree(45, 92) draw_pint_tree(220, 95) draw_pint_tree(250, 90) To be able to do this, I need to learn about variables, expressions, and function parameters. How to Use Variables and Expressions in a Function We can use expressions like the ones we wrote into our calculators last week, even in the calls that we make. For example, we have a draw_triangle_filled function. It takes three points to draw a triangle. It needs x1, y1, x2, y2, x3, y3. What if we wanted to center a triangle around a point, and specify a width and height?
We can use that math when we call our function to draw: center_x = 200 center_y = 200 width = 30 height = 30 arcade.draw_triangle_filled(center_x - width / 2, center_y - width / 2, center_x + width / 2, center_y - width / 2, center_x, center_y + width / 2, arcade.color.forest_green) Attention: Order of Operations aka PEMDAS apply here! Python will evaluate expressions using the same order of operations that are expected in standard mathematical expressions. For example this equation does not correctly calculate the average: average = 90 + 86 + 71 + 100 + 98 / 5 The first operation done is 98/5. By using parentheses this problem can be fixed: average = (90 + 86 + 71 + 100 + 98) / 5
How to Create a Custom Drawing Function We can call functions with parameters. When we declare a function we can put new variables between the parenthesis. See line 15 below. The two variables position_x and position_y will take whatever value is passed in when the function is called. On line 46, we call draw_pine_tree with two numbers, 70 and 90. The variable position_x will be assigned 70, and the variable position_y will be assigned 90. We can use the variables from the parameters, and some mathematical expressions to draw a tree. Line 38 draws a small red point where the origin of the tree is. That is, draws the point at (position_x, position_y). From there you can get an idea of how the other shapes relate in position. Spend some time matching the math to the origin and how it gets there. We can use the function several times as shown below: Code snippet: forest.py
1. """ 2. This is a sample program to show how to draw using functions 3. """ 4. 5. import arcade 6. 7. 8. def draw_grass(): 9. """ 10. This function draws the grass. 11. """ 12. arcade.draw_lrtb_rectangle_filled(0, 800, 200, 0, arcade.color.bitter_lime) 13. 14. 15. def draw_pine_tree(position_x, position_y): 16. """ 17. This function draws a pine tree. 18. """ 19. 20. # Draw the trunk 21. arcade.draw_rectangle_filled(position_x, position_y + 30, 30, 60, arcade.color.brown) 22. 23. # Draw three levels of triangles 24. arcade.draw_triangle_filled(position_x - 70, position_y + 60, 25. position_x + 70, position_y + 60, 26. position_x, position_y + 150, 27. arcade.color.forest_green) 28. arcade.draw_triangle_filled(position_x - 70, position_y + 100, 29. position_x + 70, position_y + 100, 30. position_x, position_y + 190, 31. arcade.color.forest_green) 32. arcade.draw_triangle_filled(position_x - 55, position_y + 150, 33. position_x + 55, position_y + 150, 34. position_x, position_y + 230, 35. arcade.color.forest_green) 36. 37. # Draw the origin point, just for reference.
38. arcade.draw_point(position_x, position_y, arcade.color.red, 4) 39. 40.arcade.open_window(800, 600, "Drawing with Functions") 41. arcade.set_background_color(arcade.color.air_superiority_blue) 42.arcade.start_render() 43. 44. 45.# Draw our pretty landscape 46.draw_grass() 47. draw_pine_tree(70, 90) 48.draw_pine_tree(150, 200) 49.draw_pine_tree(320, 180) 50.draw_pine_tree(520, 190) 51. draw_pine_tree(750, 80) 52. 53.arcade.finish_render() 54.arcade.run()
Returning and Capturing Values Functions can not only take in values, functions can also return values. For example: Function that returns two numbers added together # Add two numbers and return the results def sum_two_numbers(a, b): result = a + b return result Note: Return is not a function, and does not use parentheses. Don t doreturn(result). This only gets us halfway there. Because if we call the function now, not much happens. The numbers get added. They get returned to us. But we do nothing with the result. # This doesn't do much, because we don't capture the result sum_two_numbers(22, 15) Capturing Returned Values We need to capture the result. We do that by setting a variable equal to the value the function returned: # Store the function's result into a variable at the bottom of your code my_result = sum_two_numbers(22, 15) print(my_result) Now the result isn t lost. It is stored in my_result which we can print or use some other way. Volume Cylinder Example Function that returns the volume of a cylinder def volume_cylinder(radius, height): pi = 3.141592653589 volume = pi * radius ** 2 * height return volume Because of the return, this function could be used later on as part of an equation to calculate the volume of a six-pack like this: six_pack_volume = volume_cylinder(2.5, 5) * 6 The value returned from volume_cylinder goes into the equation and is multiplied by six. There is a big difference between a function that prints a value and a function that returns a value. Look at the code below and try it out.
# Function that prints the result def sum_print(a, b): result = a + b print(result) # Function that returns the results def sum_return(a, b): result = a + b return result # This prints the sum of 4+4 sum_print(4, 4) # This does not sum_return(4, 4) # This will not set x1 to the sum # It actually gets a value of 'None' because we can store the result of a print function into a variable x1 = sum_print(4, 4) # This will x2 = sum_return(4, 4) When first working with functions it is not unusual to get stuck looking at code like this: def calculate_average(a, b): """ Calculate an average of two numbers result = (a + b) / 2 return result x = 45 y = 56 # Wait, how do I print the result of this? calculate_average(x, y) How do we print the result of calculate_average? The program can t print result because that variable only exists inside the function. We can t just write print(result) at the end of our code, because that variable was created inside the function and cannot be used outside of it. instead, if we capture the result into a variable outside the function, we can print that variable for everyone to see. Instead, use a variable to capture the result:
def calculate_average(a, b): """ Calculate an average of two numbers result = (a + b) / 2 return result x = 45 y = 56 average = calculate_average(x, y) print(average) Attention Variable Scope The use of functions introduces the concept of scope. Scope is where in the code a variable is alive and can be accessed. For example, look at the code below: # Define a simple function that sets # x equal to 22 def f(): x = 22 # Call the function f() # This fails, x only exists in f() print(x) The last line will generate an error because x only exists inside of the f() function. The variable is created when f() is called and the memory it uses is freed as soon as f()finishes. Here s where it gets complicated. A more confusing rule is accessing variables created outside of the f() function. In the following code, x is created before the f()function, and thus can be read from inside the f() function. # Create the x variable and set to 44 x = 44 # Define a simple function that prints x def f(): print(x) # Call the function f() Variables created ahead of a function may be read inside of the function only if the function does not change the value. This code, very similar to the code above, will fail. The computer will claim it doesn t know what x is.
# Create the x variable and set to 44 x = 44 # Define a simple function that prints x def f(): x += 1 print(x) # Call the function f() Other languages have more complex rules around the creation of variables and scope than Python does. This is part of what makes Python a good introductory language! Make Everything a Function Code is easier to maintain and visualize if it is broken down into parts. Now that we know how to use functions, it is better programming practice to put everything into a function. Below is the same program we had before, but the main code has been moved into a main function. 1. """ 2. This is a sample program to show how to draw using functions 3. """ 4. 5. import arcade 6. 7. 8. def draw_grass(): 9. """ 10. This function draws the grass. 11. """ 12. arcade.draw_lrtb_rectangle_filled(0, 800, 200, 0, arcade.color.bitter_lime) 13. 14. 15.def draw_pine_tree(position_x, position_y): 16. """ 17. This function draws a pine tree. 18. """ 19.
20. # Draw the trunk 21. arcade.draw_rectangle_filled(position_x, position_y + 30, 30, 60, arcade.color.brown) 22. 23. # Draw three levels of triangles 24. arcade.draw_triangle_filled(position_x - 70, position_y + 60, 25. position_x + 70, position_y + 60, 26. position_x, position_y + 150, 27. arcade.color.forest_green) 28. arcade.draw_triangle_filled(position_x - 70, position_y + 100, 29. position_x + 70, position_y + 100, 30. position_x, position_y + 190, 31. arcade.color.forest_green) 32. arcade.draw_triangle_filled(position_x - 55, position_y + 150, 33. position_x + 55, position_y + 150, 34. position_x, position_y + 230, 35. arcade.color.forest_green) 36. 37. # Draw the origin point, just for reference. 38. arcade.draw_point(position_x, position_y, arcade.color.red, 4) 39. 40. 41.def main(): 42. """ 43. This is the main function that we call to run our program. 44. """ 45. arcade.open_window(800, 600, "Drawing with Functions") 46. arcade.set_background_color(arcade.color.air_superiority_blue) 47. arcade.start_render() 48. 49. # Draw our pretty landscape 50. draw_grass() 51. draw_pine_tree(70, 90) 52. draw_pine_tree(150, 200) 53. draw_pine_tree(320, 180) 54. draw_pine_tree(520, 190) 55. draw_pine_tree(750, 80) 56.
57. arcade.finish_render() 58. arcade.run() 59. 60.# Call the main function to get the program started. 61.if name == " main ": 62. main() Activity: Drawing With Functions (45 min) As outlined below, it may be easiest for students to start by combining the drawings they created in Session 2 with the code snippets they step through in the lecture, tree.py and forest.py, than to start from scratch. Instructions:! Start with the same PyCharm project you used for previous sessions. Create a new directory for Session 4. Make sure it is not inside of the folders for Sessions 1, 2, or 3. Feel free to use any code from previous weeks you want, just copy it across. It may be easiest to rework your drawing_picture.py to use functions.! Put any code you will need in a new file under Session 4, called functions.py! HINT: Instead of calling a certain shape-drawing function already built for you with coordinates, start with a coordinate x, a coordinate y, and tell it the line how far to extend. See the tree.py, grass.py, and forest.py code snippets for reference.! If you want to start from scratch: Create three functions that draw something. Define the function and successfully call it. Make your drawing function complex. Try not to copy from earlier examples, and have multiple lines in your function definition. Pass in x and y parameters and successfully position the object. BONUS: put everything into a main() function as exemplified at the end of the lesson.