1. Exercises: Geomagical Codemysticism¶
In the first actual programming exercises we're gonna practice some very basics of programming: solving problems, partitioning solutions and using Python to solve implement the solution. Although we don't know much about programming yet that doesn't prevent us from taking a professional, methodological approach towards victory. A good programming process is best developed while the problems themselves are still simple and there's much less fuss about tricky details. To make it easier to just focus on the problem itself, we've made the exercises mostly just math. We're just approaching these problems from a programming perspective.
We're not asking you to develop a programming process out of thin air. The tasks this time around have more of a demonstrative nature that shows you how to proceed. The things you learn here will serve you well enough for the first half of the course.
Learning Goals¶
The crux of these exercises is to get initiated into the programming process. This includes partitioning a problem's solution so that it can be described explicitly, step-by-step. Explicity is key in programming because the computer only understands exact instructions - it cannot guess what you meant. Second part of the process is recognizing how the tools at hand - in our case Python - fit into each stage of the solution.
There's also more concrete, technical aims for this exercise. We have two very integral programming concepts:
variables
and functions
. We will also pay attention to how information moves between different parts of the program - especially between functions. Of course we'll also learn syntax
for how to write these basic things in Python. The exercise also includes a little bit of taking input
from the user.Example¶
Task¶
Balls are a bit tricky to measure. The easiest measurement to get is the circumference but what if you're asked for volume or surface area? You've also been given scores of balls to measure... This would be a good time to make a program that calculates these two quantities from the circumference.
Solution¶
The ultimate goal is to solve two mystery values: ball volume and surface area. The first step towards victory is finding out how these quantities are calculated in general. It's important to start from the answer because this helps us figure out what can be done with the information we actually have. Both quantities have their own separate formulas that we can recall from school geometry or Wikipedia.
V = 4 / 3 * pi * r^3 A = 4 * pi * r^2
These almost look like program code already! Both formulas have two "unknowns": pi and r. We do know what pi is though, and we even know that we can obtain a very good estimate for its value from the math
module
. All that's left is the radius, r. Before figuring that one out we can already write some code though so let's do that before we forget these formulas. Let's start from the end of the material: using import
. All imports should be in the beginning of code, so it' usually a good place to start:import math
We can also write two
functions
: one for the area and another for the volume. It's best to make each of these into their own function so that we can calculate them for any balls - that's what we wanted initially after all. The result for both formulas depends on the ball's radius which makes it a natural choice to a function parameter
. The functions should probably return the results as well. This gives us two function definitions that we can stick after the import statement:import math
def calculate_area(radius):
return 4 * math.pi * radius ** 2
def calculate_volume(radius):
return 4 / 3 * math.pi * radius ** 3
One thing to remember is that exponentiation is done with the
**
operator
. After this we need to figure how to get the radius. We know the circumference which is the same as the diameter of the ball's cross section. Because of the shape of the ball, the radius of the cross section circumference is the same as the ball's radius. We also have a formula for calculating the circumference of a cicle:
c = 2 * pi * r
We can spin this around a bit so that we can calculate r from c instead:
r = c / (2 * pi)
This can also be turned into its own
function
that calculates a radius when called with circumference of a circle as as argument
. Let's add this function to the pile with the rest and we'll have something like this:import math
def calculate_area(radius):
return 4 * math.pi * radius ** 2
def calculate_volume(radius):
return 4 / 3 * math.pi * radius ** 3
def calculate_radius(circumference):
return circumference / (math.pi * 2)
At this stage we've solved all the sub problems and the solutions are neatly in their own functions. All that's left is to solve the main problem. We can do this in another function called calculate_ball_properties:
def calculate_ball_properties(circumference):
radius = calculate_radius(circumference)
area = calculate_area(radius)
volume = calculate_volume(radius)
return area, volume
This
function
gets the measured circumference as a parameter
. After this the process is rather straightforward. First we calculate the radius of the ball usng the function we just made for this purpose and then the properties we wanted to know in the first place. What's significant about this function is that the process is very clear just from reading the names of the functions that are called. All that's left to do is to round the results and show them. Rounding should only be done when the results are printed because as we've learned from math you should not round values
that can still be used in further calculations. Therefore it's best to do it in the main program
where this function is called. We also need to get the circumference from somewhere. That's done by prompting it from the user like we learned at the end of the material:measurement = float(input("Enter ball circumference: "))
ball_area, ball_volume = calculate_ball_properties(measurement)
print("Volume:", round(ball_volume, 4))
print("Surface area:", round(ball_area, 4))
And here's the completed code:
Naming Files¶
A Python code file is recognized from its .py extension. The name itself doesn't matter much for Python but there are some rules. Names for files follow the same rules as variables: only lowercase letters, numbers and underscores should be used. Filenames that contain other characters cannot be
imported
which causes problems, especially for checking because the checking programs will import your code file in order to test it. Names should also only use the English alphabet on this course. Therefore these are not good names:first exercise.py surströmming.py e1.5.py donkey-swings++.py
Underscores should be used to separate words and letters should be replaced with their closest English equivalent. The same names fixed:
first_exercise.py surstromming.py e1_5.py donkey_swings.py
Checking Programs¶
On this course all programming exercises are checked with specialized checking programs (checkers). A typical assignment will consist of defining one or more
functions
and a main program
that uses them. It's important to understand that these are always checked separately. This is particularly important for functions because any functions that don't follow the exercise instructions will not pass. Functions need to do exactly the things that are described, no more, no less. They also must look exactly as described to the rest of the program. These means they must have the specified name and exactly the same parameters
in the specified order. Finally they must return
a value that matches what's been specified in the assignment. If a function's name is wrong the checker simply cannot find it. If the number of parameters doesn't match the specification, the function cannot be called be the checker with its test arguments. If the order of the parameters is wrong the function will either not work at all or will give incorrect result. An example of incorrect results is the fourth exercise where a function has to calculate the area of a sector using two parameters. If these are swapped, the results will obviously be wrong because the function ends up using radius as the angle and vice versa. Typically a function is tested by comparing its returned value(s) to value(s) returned by the reference implementation. If the results have the wrong type these comparisons will fail and the program won't pass the test.
In most cases the tests have been configured to check the program with both random values and potential edge cases (e.g. invalid inputs, zero, very small and very big numbers etc.) Typically each
function
in the program will be called repeatedly with different arguments
during testing (most commonly 10 times). Because of this it's important to make sure the function works like a strong independent function that doesn't need no values from the global scope
. This means that any values it uses should be from its own parameters
. Keep this in mind in the main task of this exercise where you need to calculate the surface area of a figure from a the length of a single edge. All calculations must happen inside the function! If you do some of the calculations in the main program
the function won't work correctly when it's taken out of context. The checkers will always try to tell you what they attempted to do so that you can figure out why your solution didn't pass. Typically they will tell you what values were used in each test case and what result was returned with those values. They also show what should have been returned in case the result was wrong. In some cases the results will also be compared with references that contain errors typical to the exercise. This way the checkers can sometimes give extra information about what probably went wrong. The checkers are not very helpful for solving problems that prevent the program from running in the first place. Make sure your program actually works on your own computer before sending it to the checker! When you run programs in your own computer's
terminal
you will get much more information about why it doesn't run. Checkers can also give misleading information for broken programs because their exception handling assumes the program works, and will interpret error situations with this assumption. Testing Your Code in the Python Console¶
Given that the checkers often test your
functions
independently it is often easier to solve problems if you can also easily call your functions with different values. You can always do this by copying the function definition to the Python console
but a more robust solution is to learn how to import
your functions to the console. Let's look at an example of using functions from the example in this material. First it should be saved to some suitable folder with a good name like ball.py
. At this stage it's easiest to always be in the same folder as your code file
that you want to execute. So first let's move there in the terminal (see instructions if needed) and start the console by typing ipython
.Functions from a code file can be used in the console using either a normal import statement or a from-import statement. Regardless of how it is imported, the code file will always be executed. The first thing that happens is therefore that it will ask for inputs as prompted in the
main program
. This is not exactly desired behavior, and later we'll learn how to avoid it. For now though we'll just put some numbers there to proceed. After that the functions can be called directly from the console:About Code Quality Tests¶
We have also attached a code quality check to each checking program using a tool called Pylint. The evaluation is based on Python's PEP8 style standard. Some notifications have been disabled but otherwise Pylint scoring is used as-is. The evaluation is used in grading the course, giving you an extra point for an accepted submission if your style score is 9 or higher. In general paying attention to the notifications and fixing the problems helps you write code that's not only easier to read but also less prone to errors. It's also much easier to fix errors from code that has received high points from Pylint.
Warmup Exercise¶
Exercises¶
Course Project Considerations¶
How do these exercises relate to the course project? Obviously it's difficult to anything at all without knowing the basics. That's not all we learned though. We also learned a skill that's essential for writing larger programs: splitting the implementation into functions. Just by thinking about function names that will be included in the final program can lead you surprisingly close to the solution. Such a function plan need not be final. Regardless it is the very first concrete representation of what the code could contain and what kinds of things could happen in the program.
Give feedback on this content
Comments about these exercises