Last active
June 15, 2021 18:29
-
-
Save cjtu/35f0f3f66f60b5c996ebb3140a675a78 to your computer and use it in GitHub Desktop.
Swimming with snakes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"metadata": { | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": 3 | |
}, | |
"orig_nbformat": 4 | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2, | |
"cells": [ | |
{ | |
"source": [ | |
"# Swimming with Snakes\n", | |
"\n", | |
"A short tutorial about designing a model to maintain a swimming pool in Python.\n", | |
"\n", | |
"This tutorial covers:\n", | |
"\n", | |
"- Designing a Python program to be *flexible* and *modular*\n", | |
"- Breaking code down into *functions*\n", | |
"- Using vectors rather than loops for *efficiency*\n", | |
"- Writing *readable* programs with good style\n", | |
"\n", | |
"## Step 1: Picture this\n", | |
"\n", | |
"Say you want to model the water level of a swimming pool over the course of a typical day. Over time, the pool drains at 10% of its current level per hour. The pump refills it at 10 cm / hour and stops when the water is at least 2 m deep. Other things influenced the water level on this particular day:\n", | |
"\n", | |
"- 00:00 The pool water level is kept at 2 m when the pool is closed\n", | |
"- 09:00 Pool opens at a water level of 2 m\n", | |
"- 10:00 A group of swimmers arrive rasing the water level 50 cm for half an hour\n", | |
"- 11:00 The pool is closed and 10 cm of chlorine is added over 5 minutes\n", | |
"- 13:00 A swimming class arrives, raising the water level 25 cm for one hour\n", | |
"- 14:00 It rains heavily and accumulates 10 cm in 45 minutes\n", | |
"- 15:00 The pump breaks, causing the pool to drain but not refill for one hour\n", | |
"- 16:00 The pump is fixed but now pumps at a new rate such that it takes an hour to fill the pool back to 2 m\n", | |
"- 17:00 The pool closes and remains at 2 m overnight\n", | |
"\n", | |
"\n", | |
"Your goal is to write a Python function that returns the water level of the swimming pool at a given time in the day (0, 24h).\n", | |
"\n", | |
"\n", | |
"## Step 2: Pen & Paper / Whiteboard\n", | |
"\n", | |
"The first step to any programming problem is to write (yes physically) out everything you know, don't know, and think you may need to find in order to solve your problem. As the old adage goes:\n", | |
"\n", | |
"> 5 hours of coding can save you 10 minutes of planning!\n", | |
"\n", | |
"Here is where we can start to think about what the structure of our program might look like. Take about five minutes to plan out your code on a piece of paper or whiteboard and then continue with the next section.\n", | |
"\n", | |
"\n", | |
"## Step 3: Documentation and pseudocode first!\n", | |
"\n", | |
"In science, time is often short and it's useful to be able to try things quickly. This is encouraged! The important thing is trying things in a way that you can easily place them into a program when you're done.\n", | |
"\n", | |
"One technique that will save time in the long run is to first write a skeleton / outline of your program with no real code (just write everything in plain english or \"pseudocode\" to start). As you test each line or segment, you can drop those code snippets into your skeleton version.\n", | |
"\n", | |
"In the next section, write convert the outline of your program that you wrote on the piece of paper to a \"skeleton\" version. This version should not have any code, except possibly function definitions and their return values (optional). Docstrings and comments are highly encouraged. See example below:\n", | |
"\n" | |
], | |
"cell_type": "markdown", | |
"metadata": {} | |
}, | |
{ | |
"source": [ | |
"\"\"\"Write your swimming pool code skeleton here.\"\"\"\n", | |
"# I will import modules here\n", | |
"\n", | |
"# I will define constants here\n", | |
"\n", | |
"# Functions I think I'll need are:\n", | |
"\n", | |
"def water_level(t):\n", | |
" \"\"\"\n", | |
" Return the water level of the swimming pool at time t.\n", | |
"\n", | |
" Parameters\n", | |
" ----------\n", | |
" t (num): A given time in decimals in the range (0, 24) [hours]\n", | |
"\n", | |
" Return\n", | |
" ------\n", | |
" water_level (num): The swimming pool water level at time t.\n", | |
" \"\"\"\n", | |
" # The first thing I need to do is...\n", | |
"\n", | |
" # Then I will have to...\n", | |
"\n", | |
" # Finally I will get the water level with something like\n", | |
" # water_level at time t = blah\n", | |
"\n", | |
" # Here I will return the water level\n", | |
" pass\n", | |
"\n", | |
"# Other things I'll need to do" | |
], | |
"cell_type": "code", | |
"metadata": {}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"source": [ | |
"## Step 4: Time to code\n", | |
"\n", | |
"Now you can start filling in your functions, replacing pseudocode and comments with actual code, etc. I find it's nice to test things out in a Jupyter noebook and then copy my working lines of code into my skeleton. \n", | |
"\n", | |
"Feel free to use the code block below to test out your code (don't forget to copy it back into your skeleton as you finish components)." | |
], | |
"cell_type": "markdown", | |
"metadata": {} | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# Write code here\n" | |
] | |
}, | |
{ | |
"source": [ | |
"## Step 5: Testing your code\n", | |
"\n", | |
"Your priorities when writing code should be:\n", | |
"\n", | |
"1. The code works.\n", | |
"2. The code is commented/documented so others can understand it (or future you, who won't remember writing it).\n", | |
"3. The code is readable by others (and future you).\n", | |
"4. The code doesn't repeat itself unecessarily.\n", | |
"4. The code is easy to edit, update, and extend.\n", | |
"5. ...\n", | |
"\n", | |
"\n", | |
"100. The code is efficient.\n", | |
"\n", | |
"It doesn't matter how efficient you code is if it doesn't do what you want it to do. That is why testing your code is important. A common practice in software development is to write code that tests your code and there are many tools and tutorials out there to get you started with *unittesting*. For now, let's do a simplified version.\n", | |
"\n", | |
"The basic idea behind testing is to run pieces of your code and see if they produce the values you expected. If you're having a hard time thinking up good tests, just remember when you were trying out lines of code to make sure they worked, how did you know that they worked?\n", | |
"\n", | |
"There are two tests from the problem below, but see if you can come up with more, especially for the different aspects of your program." | |
], | |
"cell_type": "markdown", | |
"metadata": {} | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"print('Test: 9 AM pool is 2m')\n", | |
"print(water_level(9) == 2)\n", | |
"\n", | |
"print('Test: 5 PM pool is 2m')\n", | |
"print(water_level(17) == 2)\n", | |
"\n", | |
"print('Tests: Overnight pool is 2m')\n", | |
"print(water_level(20) == 2)\n", | |
"print(water_level(22.5) == 2)\n", | |
"print(water_level(0) == 2)\n", | |
"print(water_level(2.25) == 2)\n" | |
] | |
}, | |
{ | |
"source": [], | |
"cell_type": "markdown", | |
"metadata": {} | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment