diff --git a/02-Python Statements/.ipynb_checkpoints/09-Guessing Game Challenge-checkpoint.ipynb b/02-Python Statements/.ipynb_checkpoints/09-Guessing Game Challenge-checkpoint.ipynb
new file mode 100644
index 000000000..97f6fb7eb
--- /dev/null
+++ b/02-Python Statements/.ipynb_checkpoints/09-Guessing Game Challenge-checkpoint.ipynb
@@ -0,0 +1,154 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Guessing Game Challenge\n",
+ "\n",
+ "Let's use `while` loops to create a guessing game.\n",
+ "\n",
+ "The Challenge:\n",
+ "\n",
+ "Write a program that picks a random integer from 1 to 100, and has players guess the number. The rules are:\n",
+ "\n",
+ "1. If a player's guess is less than 1 or greater than 100, say \"OUT OF BOUNDS\"\n",
+ "2. On a player's first turn, if their guess is\n",
+ " * within 10 of the number, return \"WARM!\"\n",
+ " * further than 10 away from the number, return \"COLD!\"\n",
+ "3. On all subsequent turns, if a guess is \n",
+ " * closer to the number than the previous guess return \"WARMER!\"\n",
+ " * farther from the number than the previous guess, return \"COLDER!\"\n",
+ "4. When the player's guess equals the number, tell them they've guessed correctly *and* how many guesses it took!\n",
+ "\n",
+ "You can try this from scratch, or follow the steps outlined below. A separate Solution notebook has been provided. Good luck!\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### First, pick a random integer from 1 to 100 using the random module and assign it to a variable\n",
+ "\n",
+ "Note: `random.randint(a,b)` returns a random integer in range `[a, b]`, including both end points."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Next, print an introduction to the game and explain the rules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Create a list to store guesses\n",
+ "\n",
+ "Hint: zero is a good placeholder value. It's useful because it evaluates to \"False\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Write a `while` loop that asks for a valid guess. Test it a few times to make sure it works."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "while True:\n",
+ " \n",
+ " pass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Write a `while` loop that compares the player's guess to our number. If the player guesses correctly, break from the loop. Otherwise, tell the player if they're warmer or colder, and continue asking for guesses.\n",
+ "\n",
+ "Some hints:\n",
+ "* it may help to sketch out all possible combinations on paper first!\n",
+ "* you can use the `abs()` function to find the positive difference between two numbers\n",
+ "* if you append all new guesses to the list, then the previous guess is given as `guesses[-2]`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "while True:\n",
+ "\n",
+ " # we can copy the code from above to take an input\n",
+ "\n",
+ " pass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "That's it! You've just programmed your first game!\n",
+ "\n",
+ "In the next section we'll learn how to turn some of these repetitive actions into *functions* that can be called whenever we need them."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Good Job!"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "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.6.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/02-Python Statements/.ipynb_checkpoints/10-Guessing Game Challenge - Solution-checkpoint.ipynb b/02-Python Statements/.ipynb_checkpoints/10-Guessing Game Challenge - Solution-checkpoint.ipynb
new file mode 100644
index 000000000..3df229e00
--- /dev/null
+++ b/02-Python Statements/.ipynb_checkpoints/10-Guessing Game Challenge - Solution-checkpoint.ipynb
@@ -0,0 +1,258 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Guessing Game Challenge - Solution\n",
+ "\n",
+ "Let's use `while` loops to create a guessing game.\n",
+ "\n",
+ "The Challenge:\n",
+ "\n",
+ "Write a program that picks a random integer from 1 to 100, and has players guess the number. The rules are:\n",
+ "\n",
+ "1. If a player's guess is less than 1 or greater than 100, say \"OUT OF BOUNDS\"\n",
+ "2. On a player's first turn, if their guess is\n",
+ " * within 10 of the number, return \"WARM!\"\n",
+ " * further than 10 away from the number, return \"COLD!\"\n",
+ "3. On all subsequent turns, if a guess is \n",
+ " * closer to the number than the previous guess return \"WARMER!\"\n",
+ " * farther from the number than the previous guess, return \"COLDER!\"\n",
+ "4. When the player's guess equals the number, tell them they've guessed correctly *and* how many guesses it took!\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### First, pick a random integer from 1 to 100 using the random module and assign it to a variable\n",
+ "\n",
+ "Note: `random.randint(a,b)` returns a random integer in range `[a, b]`, including both end points."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import random\n",
+ "\n",
+ "num = random.randint(1,100)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Next, print an introduction to the game and explain the rules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "WELCOME TO GUESS ME!\n",
+ "I'm thinking of a number between 1 and 100\n",
+ "If your guess is more than 10 away from my number, I'll tell you you're COLD\n",
+ "If your guess is within 10 of my number, I'll tell you you're WARM\n",
+ "If your guess is farther than your most recent guess, I'll say you're getting COLDER\n",
+ "If your guess is closer than your most recent guess, I'll say you're getting WARMER\n",
+ "LET'S PLAY!\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(\"WELCOME TO GUESS ME!\")\n",
+ "print(\"I'm thinking of a number between 1 and 100\")\n",
+ "print(\"If your guess is more than 10 away from my number, I'll tell you you're COLD\")\n",
+ "print(\"If your guess is within 10 of my number, I'll tell you you're WARM\")\n",
+ "print(\"If your guess is farther than your most recent guess, I'll say you're getting COLDER\")\n",
+ "print(\"If your guess is closer than your most recent guess, I'll say you're getting WARMER\")\n",
+ "print(\"LET'S PLAY!\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Create a list to store guesses\n",
+ "\n",
+ "Hint: zero is a good placeholder value. It's useful because it evaluates to \"False\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "guesses = [0]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Write a `while` loop that asks for a valid guess. Test it a few times to make sure it works."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 500\n",
+ "OUT OF BOUNDS! Please try again: \n",
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 50\n"
+ ]
+ }
+ ],
+ "source": [
+ "while True:\n",
+ " \n",
+ " guess = int(input(\"I'm thinking of a number between 1 and 100.\\n What is your guess? \"))\n",
+ " \n",
+ " if guess < 1 or guess > 100:\n",
+ " print('OUT OF BOUNDS! Please try again: ')\n",
+ " continue\n",
+ " \n",
+ " break"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Write a `while` loop that compares the player's guess to our number. If the player guesses correctly, break from the loop. Otherwise, tell the player if they're warmer or colder, and continue asking for guesses.\n",
+ "\n",
+ "Some hints:\n",
+ "* it may help to sketch out all possible combinations on paper first!\n",
+ "* you can use the `abs()` function to find the positive difference between two numbers\n",
+ "* if you append all new guesses to the list, then the previous guess is given as `guesses[-2]`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 50\n",
+ "COLD!\n",
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 75\n",
+ "WARMER!\n",
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 85\n",
+ "WARMER!\n",
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 92\n",
+ "COLDER!\n",
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 80\n",
+ "WARMER!\n",
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 78\n",
+ "COLDER!\n",
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 82\n",
+ "WARMER!\n",
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 83\n",
+ "COLDER!\n",
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 81\n",
+ "CONGRATULATIONS, YOU GUESSED IT IN ONLY 9 GUESSES!!\n"
+ ]
+ }
+ ],
+ "source": [
+ "while True:\n",
+ "\n",
+ " # we can copy the code from above to take an input\n",
+ " guess = int(input(\"I'm thinking of a number between 1 and 100.\\n What is your guess? \"))\n",
+ " \n",
+ " if guess < 1 or guess > 100:\n",
+ " print('OUT OF BOUNDS! Please try again: ')\n",
+ " continue\n",
+ " \n",
+ " # here we compare the player's guess to our number\n",
+ " if guess == num:\n",
+ " print(f'CONGRATULATIONS, YOU GUESSED IT IN ONLY {len(guesses)} GUESSES!!')\n",
+ " break\n",
+ " \n",
+ " # if guess is incorrect, add guess to the list\n",
+ " guesses.append(guess)\n",
+ " \n",
+ " # when testing the first guess, guesses[-2]==0, which evaluates to False\n",
+ " # and brings us down to the second section\n",
+ " \n",
+ " if guesses[-2]: \n",
+ " if abs(num-guess) < abs(num-guesses[-2]):\n",
+ " print('WARMER!')\n",
+ " else:\n",
+ " print('COLDER!')\n",
+ " \n",
+ " else:\n",
+ " if abs(num-guess) <= 10:\n",
+ " print('WARM!')\n",
+ " else:\n",
+ " print('COLD!')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "That's it! You've just programmed your first game!\n",
+ "\n",
+ "In the next section we'll learn how to turn some of these repetitive actions into *functions* that can be called whenever we need them."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Good Job!"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "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.6.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/02-Python Statements/09-Guessing Game Challenge.ipynb b/02-Python Statements/09-Guessing Game Challenge.ipynb
new file mode 100644
index 000000000..97f6fb7eb
--- /dev/null
+++ b/02-Python Statements/09-Guessing Game Challenge.ipynb
@@ -0,0 +1,154 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Guessing Game Challenge\n",
+ "\n",
+ "Let's use `while` loops to create a guessing game.\n",
+ "\n",
+ "The Challenge:\n",
+ "\n",
+ "Write a program that picks a random integer from 1 to 100, and has players guess the number. The rules are:\n",
+ "\n",
+ "1. If a player's guess is less than 1 or greater than 100, say \"OUT OF BOUNDS\"\n",
+ "2. On a player's first turn, if their guess is\n",
+ " * within 10 of the number, return \"WARM!\"\n",
+ " * further than 10 away from the number, return \"COLD!\"\n",
+ "3. On all subsequent turns, if a guess is \n",
+ " * closer to the number than the previous guess return \"WARMER!\"\n",
+ " * farther from the number than the previous guess, return \"COLDER!\"\n",
+ "4. When the player's guess equals the number, tell them they've guessed correctly *and* how many guesses it took!\n",
+ "\n",
+ "You can try this from scratch, or follow the steps outlined below. A separate Solution notebook has been provided. Good luck!\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### First, pick a random integer from 1 to 100 using the random module and assign it to a variable\n",
+ "\n",
+ "Note: `random.randint(a,b)` returns a random integer in range `[a, b]`, including both end points."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Next, print an introduction to the game and explain the rules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Create a list to store guesses\n",
+ "\n",
+ "Hint: zero is a good placeholder value. It's useful because it evaluates to \"False\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Write a `while` loop that asks for a valid guess. Test it a few times to make sure it works."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "while True:\n",
+ " \n",
+ " pass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Write a `while` loop that compares the player's guess to our number. If the player guesses correctly, break from the loop. Otherwise, tell the player if they're warmer or colder, and continue asking for guesses.\n",
+ "\n",
+ "Some hints:\n",
+ "* it may help to sketch out all possible combinations on paper first!\n",
+ "* you can use the `abs()` function to find the positive difference between two numbers\n",
+ "* if you append all new guesses to the list, then the previous guess is given as `guesses[-2]`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "while True:\n",
+ "\n",
+ " # we can copy the code from above to take an input\n",
+ "\n",
+ " pass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "That's it! You've just programmed your first game!\n",
+ "\n",
+ "In the next section we'll learn how to turn some of these repetitive actions into *functions* that can be called whenever we need them."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Good Job!"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "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.6.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/02-Python Statements/10-Guessing Game Challenge - Solution.ipynb b/02-Python Statements/10-Guessing Game Challenge - Solution.ipynb
new file mode 100644
index 000000000..3df229e00
--- /dev/null
+++ b/02-Python Statements/10-Guessing Game Challenge - Solution.ipynb
@@ -0,0 +1,258 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Guessing Game Challenge - Solution\n",
+ "\n",
+ "Let's use `while` loops to create a guessing game.\n",
+ "\n",
+ "The Challenge:\n",
+ "\n",
+ "Write a program that picks a random integer from 1 to 100, and has players guess the number. The rules are:\n",
+ "\n",
+ "1. If a player's guess is less than 1 or greater than 100, say \"OUT OF BOUNDS\"\n",
+ "2. On a player's first turn, if their guess is\n",
+ " * within 10 of the number, return \"WARM!\"\n",
+ " * further than 10 away from the number, return \"COLD!\"\n",
+ "3. On all subsequent turns, if a guess is \n",
+ " * closer to the number than the previous guess return \"WARMER!\"\n",
+ " * farther from the number than the previous guess, return \"COLDER!\"\n",
+ "4. When the player's guess equals the number, tell them they've guessed correctly *and* how many guesses it took!\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### First, pick a random integer from 1 to 100 using the random module and assign it to a variable\n",
+ "\n",
+ "Note: `random.randint(a,b)` returns a random integer in range `[a, b]`, including both end points."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import random\n",
+ "\n",
+ "num = random.randint(1,100)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Next, print an introduction to the game and explain the rules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "WELCOME TO GUESS ME!\n",
+ "I'm thinking of a number between 1 and 100\n",
+ "If your guess is more than 10 away from my number, I'll tell you you're COLD\n",
+ "If your guess is within 10 of my number, I'll tell you you're WARM\n",
+ "If your guess is farther than your most recent guess, I'll say you're getting COLDER\n",
+ "If your guess is closer than your most recent guess, I'll say you're getting WARMER\n",
+ "LET'S PLAY!\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(\"WELCOME TO GUESS ME!\")\n",
+ "print(\"I'm thinking of a number between 1 and 100\")\n",
+ "print(\"If your guess is more than 10 away from my number, I'll tell you you're COLD\")\n",
+ "print(\"If your guess is within 10 of my number, I'll tell you you're WARM\")\n",
+ "print(\"If your guess is farther than your most recent guess, I'll say you're getting COLDER\")\n",
+ "print(\"If your guess is closer than your most recent guess, I'll say you're getting WARMER\")\n",
+ "print(\"LET'S PLAY!\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Create a list to store guesses\n",
+ "\n",
+ "Hint: zero is a good placeholder value. It's useful because it evaluates to \"False\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "guesses = [0]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Write a `while` loop that asks for a valid guess. Test it a few times to make sure it works."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 500\n",
+ "OUT OF BOUNDS! Please try again: \n",
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 50\n"
+ ]
+ }
+ ],
+ "source": [
+ "while True:\n",
+ " \n",
+ " guess = int(input(\"I'm thinking of a number between 1 and 100.\\n What is your guess? \"))\n",
+ " \n",
+ " if guess < 1 or guess > 100:\n",
+ " print('OUT OF BOUNDS! Please try again: ')\n",
+ " continue\n",
+ " \n",
+ " break"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Write a `while` loop that compares the player's guess to our number. If the player guesses correctly, break from the loop. Otherwise, tell the player if they're warmer or colder, and continue asking for guesses.\n",
+ "\n",
+ "Some hints:\n",
+ "* it may help to sketch out all possible combinations on paper first!\n",
+ "* you can use the `abs()` function to find the positive difference between two numbers\n",
+ "* if you append all new guesses to the list, then the previous guess is given as `guesses[-2]`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 50\n",
+ "COLD!\n",
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 75\n",
+ "WARMER!\n",
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 85\n",
+ "WARMER!\n",
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 92\n",
+ "COLDER!\n",
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 80\n",
+ "WARMER!\n",
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 78\n",
+ "COLDER!\n",
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 82\n",
+ "WARMER!\n",
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 83\n",
+ "COLDER!\n",
+ "I'm thinking of a number between 1 and 100.\n",
+ " What is your guess? 81\n",
+ "CONGRATULATIONS, YOU GUESSED IT IN ONLY 9 GUESSES!!\n"
+ ]
+ }
+ ],
+ "source": [
+ "while True:\n",
+ "\n",
+ " # we can copy the code from above to take an input\n",
+ " guess = int(input(\"I'm thinking of a number between 1 and 100.\\n What is your guess? \"))\n",
+ " \n",
+ " if guess < 1 or guess > 100:\n",
+ " print('OUT OF BOUNDS! Please try again: ')\n",
+ " continue\n",
+ " \n",
+ " # here we compare the player's guess to our number\n",
+ " if guess == num:\n",
+ " print(f'CONGRATULATIONS, YOU GUESSED IT IN ONLY {len(guesses)} GUESSES!!')\n",
+ " break\n",
+ " \n",
+ " # if guess is incorrect, add guess to the list\n",
+ " guesses.append(guess)\n",
+ " \n",
+ " # when testing the first guess, guesses[-2]==0, which evaluates to False\n",
+ " # and brings us down to the second section\n",
+ " \n",
+ " if guesses[-2]: \n",
+ " if abs(num-guess) < abs(num-guesses[-2]):\n",
+ " print('WARMER!')\n",
+ " else:\n",
+ " print('COLDER!')\n",
+ " \n",
+ " else:\n",
+ " if abs(num-guess) <= 10:\n",
+ " print('WARM!')\n",
+ " else:\n",
+ " print('COLD!')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "That's it! You've just programmed your first game!\n",
+ "\n",
+ "In the next section we'll learn how to turn some of these repetitive actions into *functions* that can be called whenever we need them."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Good Job!"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "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.6.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/03-Methods and Functions/.ipynb_checkpoints/03-Function Practice Exercises-checkpoint.ipynb b/03-Methods and Functions/.ipynb_checkpoints/03-Function Practice Exercises-checkpoint.ipynb
index 709bc6769..e448be126 100644
--- a/03-Methods and Functions/.ipynb_checkpoints/03-Function Practice Exercises-checkpoint.ipynb
+++ b/03-Methods and Functions/.ipynb_checkpoints/03-Function Practice Exercises-checkpoint.ipynb
@@ -328,7 +328,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "### Find 33: \n",
+ "#### FIND 33: \n",
"\n",
"Given a list of ints, return True if the array contains a 3 next to a 3 somewhere.\n",
"\n",
@@ -361,6 +361,26 @@
"has_33([1, 3, 3])"
]
},
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Check\n",
+ "has_33([1, 3, 1, 3])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Check\n",
+ "has_33([3, 1, 3])"
+ ]
+ },
{
"cell_type": "markdown",
"metadata": {},
@@ -687,7 +707,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.6.1"
+ "version": "3.6.2"
}
},
"nbformat": 4,
diff --git a/03-Methods and Functions/.ipynb_checkpoints/04-Function Practice Exercises - Solutions-checkpoint.ipynb b/03-Methods and Functions/.ipynb_checkpoints/04-Function Practice Exercises - Solutions-checkpoint.ipynb
index f0d56186d..33ea1eea2 100644
--- a/03-Methods and Functions/.ipynb_checkpoints/04-Function Practice Exercises - Solutions-checkpoint.ipynb
+++ b/03-Methods and Functions/.ipynb_checkpoints/04-Function Practice Exercises - Solutions-checkpoint.ipynb
@@ -32,9 +32,7 @@
{
"cell_type": "code",
"execution_count": 1,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": [
"def lesser_of_two_evens(a,b):\n",
@@ -98,9 +96,7 @@
{
"cell_type": "code",
"execution_count": 4,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": [
"def animal_crackers(text):\n",
@@ -163,10 +159,8 @@
},
{
"cell_type": "code",
- "execution_count": 1,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 7,
+ "metadata": {},
"outputs": [],
"source": [
"def makes_twenty(n1,n2):\n",
@@ -175,7 +169,7 @@
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": 8,
"metadata": {},
"outputs": [
{
@@ -184,7 +178,7 @@
"True"
]
},
- "execution_count": 2,
+ "execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
@@ -196,7 +190,7 @@
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": 9,
"metadata": {},
"outputs": [
{
@@ -205,19 +199,19 @@
"True"
]
},
- "execution_count": 4,
+ "execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Check\n",
- "makes_twenty(20,10)"
+ "makes_twenty(12,8)"
]
},
{
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": 10,
"metadata": {},
"outputs": [
{
@@ -226,7 +220,7 @@
"False"
]
},
- "execution_count": 5,
+ "execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
@@ -256,10 +250,8 @@
},
{
"cell_type": "code",
- "execution_count": 10,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 11,
+ "metadata": {},
"outputs": [],
"source": [
"def old_macdonald(name):\n",
@@ -271,7 +263,7 @@
},
{
"cell_type": "code",
- "execution_count": 11,
+ "execution_count": 12,
"metadata": {},
"outputs": [
{
@@ -280,7 +272,7 @@
"'MacDonald'"
]
},
- "execution_count": 11,
+ "execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
@@ -302,10 +294,8 @@
},
{
"cell_type": "code",
- "execution_count": 12,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 13,
+ "metadata": {},
"outputs": [],
"source": [
"def master_yoda(text):\n",
@@ -314,7 +304,7 @@
},
{
"cell_type": "code",
- "execution_count": 13,
+ "execution_count": 14,
"metadata": {},
"outputs": [
{
@@ -323,7 +313,7 @@
"'home am I'"
]
},
- "execution_count": 13,
+ "execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
@@ -335,7 +325,7 @@
},
{
"cell_type": "code",
- "execution_count": 14,
+ "execution_count": 15,
"metadata": {},
"outputs": [
{
@@ -344,7 +334,7 @@
"'ready are We'"
]
},
- "execution_count": 14,
+ "execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
@@ -370,10 +360,8 @@
},
{
"cell_type": "code",
- "execution_count": 15,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 16,
+ "metadata": {},
"outputs": [],
"source": [
"def almost_there(n):\n",
@@ -382,7 +370,7 @@
},
{
"cell_type": "code",
- "execution_count": 16,
+ "execution_count": 17,
"metadata": {},
"outputs": [
{
@@ -391,7 +379,28 @@
"True"
]
},
- "execution_count": 16,
+ "execution_count": 17,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Check\n",
+ "almost_there(90)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
@@ -403,7 +412,7 @@
},
{
"cell_type": "code",
- "execution_count": 17,
+ "execution_count": 19,
"metadata": {},
"outputs": [
{
@@ -412,7 +421,7 @@
"False"
]
},
- "execution_count": 17,
+ "execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
@@ -424,7 +433,7 @@
},
{
"cell_type": "code",
- "execution_count": 18,
+ "execution_count": 20,
"metadata": {},
"outputs": [
{
@@ -433,7 +442,7 @@
"True"
]
},
- "execution_count": 18,
+ "execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
@@ -454,7 +463,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "### Find 33: \n",
+ "#### FIND 33: \n",
"\n",
"Given a list of ints, return True if the array contains a 3 next to a 3 somewhere.\n",
"\n",
@@ -465,36 +474,34 @@
},
{
"cell_type": "code",
- "execution_count": 19,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 21,
+ "metadata": {},
"outputs": [],
"source": [
"def has_33(nums):\n",
" for i in range(0, len(nums)-1):\n",
" \n",
- " # nicer looking alternative in commented code\n",
- " #if nums[i] == 3 and nums[i+1] == 3:\n",
+ " # nicer looking alternative in commented code\n",
+ " #if nums[i] == 3 and nums[i+1] == 3:\n",
" \n",
- " if nums[i:i+2] == [3,3]:\n",
- " return True \n",
+ " if nums[i:i+2] == [3,3]:\n",
+ " return True \n",
" \n",
" return False"
]
},
{
"cell_type": "code",
- "execution_count": 20,
+ "execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
- "3"
+ "True"
]
},
- "execution_count": 20,
+ "execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
@@ -504,6 +511,48 @@
"has_33([1, 3, 3])"
]
},
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 23,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Check\n",
+ "has_33([1, 3, 1, 3])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 24,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Check\n",
+ "has_33([3, 1, 3])"
+ ]
+ },
{
"cell_type": "markdown",
"metadata": {},
@@ -515,10 +564,8 @@
},
{
"cell_type": "code",
- "execution_count": 21,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 25,
+ "metadata": {},
"outputs": [],
"source": [
"def paper_doll(text):\n",
@@ -530,7 +577,7 @@
},
{
"cell_type": "code",
- "execution_count": 22,
+ "execution_count": 26,
"metadata": {},
"outputs": [
{
@@ -539,7 +586,7 @@
"'HHHeeellllllooo'"
]
},
- "execution_count": 22,
+ "execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
@@ -551,7 +598,7 @@
},
{
"cell_type": "code",
- "execution_count": 23,
+ "execution_count": 27,
"metadata": {},
"outputs": [
{
@@ -560,7 +607,7 @@
"'MMMiiissssssiiissssssiiippppppiii'"
]
},
- "execution_count": 23,
+ "execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
@@ -582,10 +629,8 @@
},
{
"cell_type": "code",
- "execution_count": 24,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 28,
+ "metadata": {},
"outputs": [],
"source": [
"def blackjack(a,b,c):\n",
@@ -600,7 +645,7 @@
},
{
"cell_type": "code",
- "execution_count": 25,
+ "execution_count": 29,
"metadata": {},
"outputs": [
{
@@ -609,7 +654,7 @@
"18"
]
},
- "execution_count": 25,
+ "execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
@@ -621,7 +666,7 @@
},
{
"cell_type": "code",
- "execution_count": 26,
+ "execution_count": 30,
"metadata": {},
"outputs": [
{
@@ -630,7 +675,7 @@
"'BUST'"
]
},
- "execution_count": 26,
+ "execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
@@ -642,7 +687,7 @@
},
{
"cell_type": "code",
- "execution_count": 27,
+ "execution_count": 31,
"metadata": {},
"outputs": [
{
@@ -651,7 +696,7 @@
"19"
]
},
- "execution_count": 27,
+ "execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
@@ -674,10 +719,8 @@
},
{
"cell_type": "code",
- "execution_count": 28,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 32,
+ "metadata": {},
"outputs": [],
"source": [
"def summer_69(arr):\n",
@@ -701,7 +744,7 @@
},
{
"cell_type": "code",
- "execution_count": 29,
+ "execution_count": 33,
"metadata": {},
"outputs": [
{
@@ -710,7 +753,7 @@
"9"
]
},
- "execution_count": 29,
+ "execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
@@ -722,7 +765,7 @@
},
{
"cell_type": "code",
- "execution_count": 30,
+ "execution_count": 34,
"metadata": {},
"outputs": [
{
@@ -731,7 +774,7 @@
"9"
]
},
- "execution_count": 30,
+ "execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
@@ -743,7 +786,7 @@
},
{
"cell_type": "code",
- "execution_count": 31,
+ "execution_count": 35,
"metadata": {},
"outputs": [
{
@@ -752,7 +795,7 @@
"14"
]
},
- "execution_count": 31,
+ "execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
@@ -782,10 +825,8 @@
},
{
"cell_type": "code",
- "execution_count": 32,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 36,
+ "metadata": {},
"outputs": [],
"source": [
"def spy_game(nums):\n",
@@ -801,7 +842,7 @@
},
{
"cell_type": "code",
- "execution_count": 33,
+ "execution_count": 37,
"metadata": {},
"outputs": [
{
@@ -810,7 +851,7 @@
"True"
]
},
- "execution_count": 33,
+ "execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
@@ -822,7 +863,7 @@
},
{
"cell_type": "code",
- "execution_count": 34,
+ "execution_count": 38,
"metadata": {},
"outputs": [
{
@@ -831,7 +872,7 @@
"True"
]
},
- "execution_count": 34,
+ "execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
@@ -843,7 +884,7 @@
},
{
"cell_type": "code",
- "execution_count": 35,
+ "execution_count": 39,
"metadata": {},
"outputs": [
{
@@ -852,7 +893,7 @@
"False"
]
},
- "execution_count": 35,
+ "execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
@@ -874,10 +915,8 @@
},
{
"cell_type": "code",
- "execution_count": 36,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 40,
+ "metadata": {},
"outputs": [],
"source": [
"def count_primes(num):\n",
@@ -900,7 +939,7 @@
},
{
"cell_type": "code",
- "execution_count": 37,
+ "execution_count": 41,
"metadata": {},
"outputs": [
{
@@ -916,7 +955,7 @@
"25"
]
},
- "execution_count": 37,
+ "execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
@@ -935,10 +974,8 @@
},
{
"cell_type": "code",
- "execution_count": 38,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 42,
+ "metadata": {},
"outputs": [],
"source": [
"def count_primes2(num):\n",
@@ -960,7 +997,7 @@
},
{
"cell_type": "code",
- "execution_count": 39,
+ "execution_count": 43,
"metadata": {},
"outputs": [
{
@@ -976,7 +1013,7 @@
"25"
]
},
- "execution_count": 39,
+ "execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
@@ -1005,10 +1042,8 @@
},
{
"cell_type": "code",
- "execution_count": 42,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 44,
+ "metadata": {},
"outputs": [],
"source": [
"def print_big(letter):\n",
@@ -1020,7 +1055,7 @@
},
{
"cell_type": "code",
- "execution_count": 43,
+ "execution_count": 45,
"metadata": {},
"outputs": [
{
@@ -1063,7 +1098,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.6.1"
+ "version": "3.6.2"
}
},
"nbformat": 4,
diff --git a/03-Methods and Functions/03-Function Practice Exercises.ipynb b/03-Methods and Functions/03-Function Practice Exercises.ipynb
index 709bc6769..e448be126 100644
--- a/03-Methods and Functions/03-Function Practice Exercises.ipynb
+++ b/03-Methods and Functions/03-Function Practice Exercises.ipynb
@@ -328,7 +328,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "### Find 33: \n",
+ "#### FIND 33: \n",
"\n",
"Given a list of ints, return True if the array contains a 3 next to a 3 somewhere.\n",
"\n",
@@ -361,6 +361,26 @@
"has_33([1, 3, 3])"
]
},
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Check\n",
+ "has_33([1, 3, 1, 3])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Check\n",
+ "has_33([3, 1, 3])"
+ ]
+ },
{
"cell_type": "markdown",
"metadata": {},
@@ -687,7 +707,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.6.1"
+ "version": "3.6.2"
}
},
"nbformat": 4,
diff --git a/03-Methods and Functions/04-Function Practice Exercises - Solutions.ipynb b/03-Methods and Functions/04-Function Practice Exercises - Solutions.ipynb
index f0d56186d..33ea1eea2 100644
--- a/03-Methods and Functions/04-Function Practice Exercises - Solutions.ipynb
+++ b/03-Methods and Functions/04-Function Practice Exercises - Solutions.ipynb
@@ -32,9 +32,7 @@
{
"cell_type": "code",
"execution_count": 1,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": [
"def lesser_of_two_evens(a,b):\n",
@@ -98,9 +96,7 @@
{
"cell_type": "code",
"execution_count": 4,
- "metadata": {
- "collapsed": true
- },
+ "metadata": {},
"outputs": [],
"source": [
"def animal_crackers(text):\n",
@@ -163,10 +159,8 @@
},
{
"cell_type": "code",
- "execution_count": 1,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 7,
+ "metadata": {},
"outputs": [],
"source": [
"def makes_twenty(n1,n2):\n",
@@ -175,7 +169,7 @@
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": 8,
"metadata": {},
"outputs": [
{
@@ -184,7 +178,7 @@
"True"
]
},
- "execution_count": 2,
+ "execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
@@ -196,7 +190,7 @@
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": 9,
"metadata": {},
"outputs": [
{
@@ -205,19 +199,19 @@
"True"
]
},
- "execution_count": 4,
+ "execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Check\n",
- "makes_twenty(20,10)"
+ "makes_twenty(12,8)"
]
},
{
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": 10,
"metadata": {},
"outputs": [
{
@@ -226,7 +220,7 @@
"False"
]
},
- "execution_count": 5,
+ "execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
@@ -256,10 +250,8 @@
},
{
"cell_type": "code",
- "execution_count": 10,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 11,
+ "metadata": {},
"outputs": [],
"source": [
"def old_macdonald(name):\n",
@@ -271,7 +263,7 @@
},
{
"cell_type": "code",
- "execution_count": 11,
+ "execution_count": 12,
"metadata": {},
"outputs": [
{
@@ -280,7 +272,7 @@
"'MacDonald'"
]
},
- "execution_count": 11,
+ "execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
@@ -302,10 +294,8 @@
},
{
"cell_type": "code",
- "execution_count": 12,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 13,
+ "metadata": {},
"outputs": [],
"source": [
"def master_yoda(text):\n",
@@ -314,7 +304,7 @@
},
{
"cell_type": "code",
- "execution_count": 13,
+ "execution_count": 14,
"metadata": {},
"outputs": [
{
@@ -323,7 +313,7 @@
"'home am I'"
]
},
- "execution_count": 13,
+ "execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
@@ -335,7 +325,7 @@
},
{
"cell_type": "code",
- "execution_count": 14,
+ "execution_count": 15,
"metadata": {},
"outputs": [
{
@@ -344,7 +334,7 @@
"'ready are We'"
]
},
- "execution_count": 14,
+ "execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
@@ -370,10 +360,8 @@
},
{
"cell_type": "code",
- "execution_count": 15,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 16,
+ "metadata": {},
"outputs": [],
"source": [
"def almost_there(n):\n",
@@ -382,7 +370,7 @@
},
{
"cell_type": "code",
- "execution_count": 16,
+ "execution_count": 17,
"metadata": {},
"outputs": [
{
@@ -391,7 +379,28 @@
"True"
]
},
- "execution_count": 16,
+ "execution_count": 17,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Check\n",
+ "almost_there(90)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
@@ -403,7 +412,7 @@
},
{
"cell_type": "code",
- "execution_count": 17,
+ "execution_count": 19,
"metadata": {},
"outputs": [
{
@@ -412,7 +421,7 @@
"False"
]
},
- "execution_count": 17,
+ "execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
@@ -424,7 +433,7 @@
},
{
"cell_type": "code",
- "execution_count": 18,
+ "execution_count": 20,
"metadata": {},
"outputs": [
{
@@ -433,7 +442,7 @@
"True"
]
},
- "execution_count": 18,
+ "execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
@@ -454,7 +463,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "### Find 33: \n",
+ "#### FIND 33: \n",
"\n",
"Given a list of ints, return True if the array contains a 3 next to a 3 somewhere.\n",
"\n",
@@ -465,36 +474,34 @@
},
{
"cell_type": "code",
- "execution_count": 19,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 21,
+ "metadata": {},
"outputs": [],
"source": [
"def has_33(nums):\n",
" for i in range(0, len(nums)-1):\n",
" \n",
- " # nicer looking alternative in commented code\n",
- " #if nums[i] == 3 and nums[i+1] == 3:\n",
+ " # nicer looking alternative in commented code\n",
+ " #if nums[i] == 3 and nums[i+1] == 3:\n",
" \n",
- " if nums[i:i+2] == [3,3]:\n",
- " return True \n",
+ " if nums[i:i+2] == [3,3]:\n",
+ " return True \n",
" \n",
" return False"
]
},
{
"cell_type": "code",
- "execution_count": 20,
+ "execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
- "3"
+ "True"
]
},
- "execution_count": 20,
+ "execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
@@ -504,6 +511,48 @@
"has_33([1, 3, 3])"
]
},
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 23,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Check\n",
+ "has_33([1, 3, 1, 3])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "False"
+ ]
+ },
+ "execution_count": 24,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Check\n",
+ "has_33([3, 1, 3])"
+ ]
+ },
{
"cell_type": "markdown",
"metadata": {},
@@ -515,10 +564,8 @@
},
{
"cell_type": "code",
- "execution_count": 21,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 25,
+ "metadata": {},
"outputs": [],
"source": [
"def paper_doll(text):\n",
@@ -530,7 +577,7 @@
},
{
"cell_type": "code",
- "execution_count": 22,
+ "execution_count": 26,
"metadata": {},
"outputs": [
{
@@ -539,7 +586,7 @@
"'HHHeeellllllooo'"
]
},
- "execution_count": 22,
+ "execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
@@ -551,7 +598,7 @@
},
{
"cell_type": "code",
- "execution_count": 23,
+ "execution_count": 27,
"metadata": {},
"outputs": [
{
@@ -560,7 +607,7 @@
"'MMMiiissssssiiissssssiiippppppiii'"
]
},
- "execution_count": 23,
+ "execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
@@ -582,10 +629,8 @@
},
{
"cell_type": "code",
- "execution_count": 24,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 28,
+ "metadata": {},
"outputs": [],
"source": [
"def blackjack(a,b,c):\n",
@@ -600,7 +645,7 @@
},
{
"cell_type": "code",
- "execution_count": 25,
+ "execution_count": 29,
"metadata": {},
"outputs": [
{
@@ -609,7 +654,7 @@
"18"
]
},
- "execution_count": 25,
+ "execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
@@ -621,7 +666,7 @@
},
{
"cell_type": "code",
- "execution_count": 26,
+ "execution_count": 30,
"metadata": {},
"outputs": [
{
@@ -630,7 +675,7 @@
"'BUST'"
]
},
- "execution_count": 26,
+ "execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
@@ -642,7 +687,7 @@
},
{
"cell_type": "code",
- "execution_count": 27,
+ "execution_count": 31,
"metadata": {},
"outputs": [
{
@@ -651,7 +696,7 @@
"19"
]
},
- "execution_count": 27,
+ "execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
@@ -674,10 +719,8 @@
},
{
"cell_type": "code",
- "execution_count": 28,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 32,
+ "metadata": {},
"outputs": [],
"source": [
"def summer_69(arr):\n",
@@ -701,7 +744,7 @@
},
{
"cell_type": "code",
- "execution_count": 29,
+ "execution_count": 33,
"metadata": {},
"outputs": [
{
@@ -710,7 +753,7 @@
"9"
]
},
- "execution_count": 29,
+ "execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
@@ -722,7 +765,7 @@
},
{
"cell_type": "code",
- "execution_count": 30,
+ "execution_count": 34,
"metadata": {},
"outputs": [
{
@@ -731,7 +774,7 @@
"9"
]
},
- "execution_count": 30,
+ "execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
@@ -743,7 +786,7 @@
},
{
"cell_type": "code",
- "execution_count": 31,
+ "execution_count": 35,
"metadata": {},
"outputs": [
{
@@ -752,7 +795,7 @@
"14"
]
},
- "execution_count": 31,
+ "execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
@@ -782,10 +825,8 @@
},
{
"cell_type": "code",
- "execution_count": 32,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 36,
+ "metadata": {},
"outputs": [],
"source": [
"def spy_game(nums):\n",
@@ -801,7 +842,7 @@
},
{
"cell_type": "code",
- "execution_count": 33,
+ "execution_count": 37,
"metadata": {},
"outputs": [
{
@@ -810,7 +851,7 @@
"True"
]
},
- "execution_count": 33,
+ "execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
@@ -822,7 +863,7 @@
},
{
"cell_type": "code",
- "execution_count": 34,
+ "execution_count": 38,
"metadata": {},
"outputs": [
{
@@ -831,7 +872,7 @@
"True"
]
},
- "execution_count": 34,
+ "execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
@@ -843,7 +884,7 @@
},
{
"cell_type": "code",
- "execution_count": 35,
+ "execution_count": 39,
"metadata": {},
"outputs": [
{
@@ -852,7 +893,7 @@
"False"
]
},
- "execution_count": 35,
+ "execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
@@ -874,10 +915,8 @@
},
{
"cell_type": "code",
- "execution_count": 36,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 40,
+ "metadata": {},
"outputs": [],
"source": [
"def count_primes(num):\n",
@@ -900,7 +939,7 @@
},
{
"cell_type": "code",
- "execution_count": 37,
+ "execution_count": 41,
"metadata": {},
"outputs": [
{
@@ -916,7 +955,7 @@
"25"
]
},
- "execution_count": 37,
+ "execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
@@ -935,10 +974,8 @@
},
{
"cell_type": "code",
- "execution_count": 38,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 42,
+ "metadata": {},
"outputs": [],
"source": [
"def count_primes2(num):\n",
@@ -960,7 +997,7 @@
},
{
"cell_type": "code",
- "execution_count": 39,
+ "execution_count": 43,
"metadata": {},
"outputs": [
{
@@ -976,7 +1013,7 @@
"25"
]
},
- "execution_count": 39,
+ "execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
@@ -1005,10 +1042,8 @@
},
{
"cell_type": "code",
- "execution_count": 42,
- "metadata": {
- "collapsed": true
- },
+ "execution_count": 44,
+ "metadata": {},
"outputs": [],
"source": [
"def print_big(letter):\n",
@@ -1020,7 +1055,7 @@
},
{
"cell_type": "code",
- "execution_count": 43,
+ "execution_count": 45,
"metadata": {},
"outputs": [
{
@@ -1063,7 +1098,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.6.1"
+ "version": "3.6.2"
}
},
"nbformat": 4,
diff --git a/05-Object Oriented Programming/.ipynb_checkpoints/01-Object Oriented Programming-checkpoint.ipynb b/05-Object Oriented Programming/.ipynb_checkpoints/01-Object Oriented Programming-checkpoint.ipynb
index c3788e212..4d9e12e27 100644
--- a/05-Object Oriented Programming/.ipynb_checkpoints/01-Object Oriented Programming-checkpoint.ipynb
+++ b/05-Object Oriented Programming/.ipynb_checkpoints/01-Object Oriented Programming-checkpoint.ipynb
@@ -758,6 +758,8 @@
"\n",
"For more great resources on this topic, check out:\n",
"\n",
+ "[Jeff Knupp's Post](https://jeffknupp.com/blog/2014/06/18/improve-your-python-python-classes-and-object-oriented-programming/)\n",
+ "\n",
"[Mozilla's Post](https://developer.mozilla.org/en-US/Learn/Python/Quickly_Learn_Object_Oriented_Programming)\n",
"\n",
"[Tutorial's Point](http://www.tutorialspoint.com/python/python_classes_objects.htm)\n",
diff --git a/05-Object Oriented Programming/.ipynb_checkpoints/04-OOP Challenge-checkpoint.ipynb b/05-Object Oriented Programming/.ipynb_checkpoints/04-OOP Challenge-checkpoint.ipynb
new file mode 100644
index 000000000..fb60ffb74
--- /dev/null
+++ b/05-Object Oriented Programming/.ipynb_checkpoints/04-OOP Challenge-checkpoint.ipynb
@@ -0,0 +1,187 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Object Oriented Programming Challenge\n",
+ "\n",
+ "For this challenge, create a bank account class that has two attributes:\n",
+ "\n",
+ "* owner\n",
+ "* balance\n",
+ "\n",
+ "and two methods:\n",
+ "\n",
+ "* deposit\n",
+ "* withdraw\n",
+ "\n",
+ "As an added requirement, withdrawals may not exceed the available balance.\n",
+ "\n",
+ "Instantiate your class, make several deposits and withdrawals, and test to make sure the account can't be overdrawn."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "class Account:\n",
+ " pass"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# 1. Instantiate the class\n",
+ "acct1 = Account('Jose',100)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Account owner: Jose\n",
+ "Account balance: $100\n"
+ ]
+ }
+ ],
+ "source": [
+ "# 2. Print the object\n",
+ "print(acct1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Jose'"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# 3. Show the account owner attribute\n",
+ "acct1.owner"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "100"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# 4. Show the account balance attribute\n",
+ "acct1.balance"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Deposit Accepted\n"
+ ]
+ }
+ ],
+ "source": [
+ "# 5. Make a series of deposits and withdrawals\n",
+ "acct1.deposit(50)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Withdrawal Accepted\n"
+ ]
+ }
+ ],
+ "source": [
+ "acct1.withdraw(75)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Funds Unavailable!\n"
+ ]
+ }
+ ],
+ "source": [
+ "# 6. Make a withdrawal that exceeds the available balance\n",
+ "acct1.withdraw(500)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Good job!"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "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.6.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/05-Object Oriented Programming/.ipynb_checkpoints/05-OOP Challenge - Solution-checkpoint.ipynb b/05-Object Oriented Programming/.ipynb_checkpoints/05-OOP Challenge - Solution-checkpoint.ipynb
new file mode 100644
index 000000000..8c71a3e91
--- /dev/null
+++ b/05-Object Oriented Programming/.ipynb_checkpoints/05-OOP Challenge - Solution-checkpoint.ipynb
@@ -0,0 +1,203 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Object Oriented Programming Challenge - Solution\n",
+ "\n",
+ "For this challenge, create a bank account class that has two attributes:\n",
+ "\n",
+ "* owner\n",
+ "* balance\n",
+ "\n",
+ "and two methods:\n",
+ "\n",
+ "* deposit\n",
+ "* withdraw\n",
+ "\n",
+ "As an added requirement, withdrawals may not exceed the available balance.\n",
+ "\n",
+ "Instantiate your class, make several deposits and withdrawals, and test to make sure the account can't be overdrawn."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "class Account:\n",
+ " def __init__(self,owner,balance=0):\n",
+ " self.owner = owner\n",
+ " self.balance = balance\n",
+ " \n",
+ " def __str__(self):\n",
+ " return f'Account owner: {self.owner}\\nAccount balance: ${self.balance}'\n",
+ " \n",
+ " def deposit(self,dep_amt):\n",
+ " self.balance += dep_amt\n",
+ " print('Deposit Accepted')\n",
+ " \n",
+ " def withdraw(self,wd_amt):\n",
+ " if self.balance >= wd_amt:\n",
+ " self.balance -= wd_amt\n",
+ " print('Withdrawal Accepted')\n",
+ " else:\n",
+ " print('Funds Unavailable!')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# 1. Instantiate the class\n",
+ "acct1 = Account('Jose',100)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Account owner: Jose\n",
+ "Account balance: $100\n"
+ ]
+ }
+ ],
+ "source": [
+ "# 2. Print the object\n",
+ "print(acct1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Jose'"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# 3. Show the account owner attribute\n",
+ "acct1.owner"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "100"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# 4. Show the account balance attribute\n",
+ "acct1.balance"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Deposit Accepted\n"
+ ]
+ }
+ ],
+ "source": [
+ "# 5. Make a series of deposits and withdrawals\n",
+ "acct1.deposit(50)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Withdrawal Accepted\n"
+ ]
+ }
+ ],
+ "source": [
+ "acct1.withdraw(75)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Funds Unavailable!\n"
+ ]
+ }
+ ],
+ "source": [
+ "# 6. Make a withdrawal that exceeds the available balance\n",
+ "acct1.withdraw(500)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Good job!"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "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.6.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/05-Object Oriented Programming/01-Object Oriented Programming.ipynb b/05-Object Oriented Programming/01-Object Oriented Programming.ipynb
index c3788e212..4d9e12e27 100644
--- a/05-Object Oriented Programming/01-Object Oriented Programming.ipynb
+++ b/05-Object Oriented Programming/01-Object Oriented Programming.ipynb
@@ -758,6 +758,8 @@
"\n",
"For more great resources on this topic, check out:\n",
"\n",
+ "[Jeff Knupp's Post](https://jeffknupp.com/blog/2014/06/18/improve-your-python-python-classes-and-object-oriented-programming/)\n",
+ "\n",
"[Mozilla's Post](https://developer.mozilla.org/en-US/Learn/Python/Quickly_Learn_Object_Oriented_Programming)\n",
"\n",
"[Tutorial's Point](http://www.tutorialspoint.com/python/python_classes_objects.htm)\n",
diff --git a/05-Object Oriented Programming/04-OOP Challenge.ipynb b/05-Object Oriented Programming/04-OOP Challenge.ipynb
new file mode 100644
index 000000000..fb60ffb74
--- /dev/null
+++ b/05-Object Oriented Programming/04-OOP Challenge.ipynb
@@ -0,0 +1,187 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Object Oriented Programming Challenge\n",
+ "\n",
+ "For this challenge, create a bank account class that has two attributes:\n",
+ "\n",
+ "* owner\n",
+ "* balance\n",
+ "\n",
+ "and two methods:\n",
+ "\n",
+ "* deposit\n",
+ "* withdraw\n",
+ "\n",
+ "As an added requirement, withdrawals may not exceed the available balance.\n",
+ "\n",
+ "Instantiate your class, make several deposits and withdrawals, and test to make sure the account can't be overdrawn."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "class Account:\n",
+ " pass"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# 1. Instantiate the class\n",
+ "acct1 = Account('Jose',100)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Account owner: Jose\n",
+ "Account balance: $100\n"
+ ]
+ }
+ ],
+ "source": [
+ "# 2. Print the object\n",
+ "print(acct1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Jose'"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# 3. Show the account owner attribute\n",
+ "acct1.owner"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "100"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# 4. Show the account balance attribute\n",
+ "acct1.balance"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Deposit Accepted\n"
+ ]
+ }
+ ],
+ "source": [
+ "# 5. Make a series of deposits and withdrawals\n",
+ "acct1.deposit(50)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Withdrawal Accepted\n"
+ ]
+ }
+ ],
+ "source": [
+ "acct1.withdraw(75)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Funds Unavailable!\n"
+ ]
+ }
+ ],
+ "source": [
+ "# 6. Make a withdrawal that exceeds the available balance\n",
+ "acct1.withdraw(500)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Good job!"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "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.6.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/05-Object Oriented Programming/05-OOP Challenge - Solution.ipynb b/05-Object Oriented Programming/05-OOP Challenge - Solution.ipynb
new file mode 100644
index 000000000..8c71a3e91
--- /dev/null
+++ b/05-Object Oriented Programming/05-OOP Challenge - Solution.ipynb
@@ -0,0 +1,203 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Object Oriented Programming Challenge - Solution\n",
+ "\n",
+ "For this challenge, create a bank account class that has two attributes:\n",
+ "\n",
+ "* owner\n",
+ "* balance\n",
+ "\n",
+ "and two methods:\n",
+ "\n",
+ "* deposit\n",
+ "* withdraw\n",
+ "\n",
+ "As an added requirement, withdrawals may not exceed the available balance.\n",
+ "\n",
+ "Instantiate your class, make several deposits and withdrawals, and test to make sure the account can't be overdrawn."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "class Account:\n",
+ " def __init__(self,owner,balance=0):\n",
+ " self.owner = owner\n",
+ " self.balance = balance\n",
+ " \n",
+ " def __str__(self):\n",
+ " return f'Account owner: {self.owner}\\nAccount balance: ${self.balance}'\n",
+ " \n",
+ " def deposit(self,dep_amt):\n",
+ " self.balance += dep_amt\n",
+ " print('Deposit Accepted')\n",
+ " \n",
+ " def withdraw(self,wd_amt):\n",
+ " if self.balance >= wd_amt:\n",
+ " self.balance -= wd_amt\n",
+ " print('Withdrawal Accepted')\n",
+ " else:\n",
+ " print('Funds Unavailable!')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# 1. Instantiate the class\n",
+ "acct1 = Account('Jose',100)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Account owner: Jose\n",
+ "Account balance: $100\n"
+ ]
+ }
+ ],
+ "source": [
+ "# 2. Print the object\n",
+ "print(acct1)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Jose'"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# 3. Show the account owner attribute\n",
+ "acct1.owner"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "100"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# 4. Show the account balance attribute\n",
+ "acct1.balance"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Deposit Accepted\n"
+ ]
+ }
+ ],
+ "source": [
+ "# 5. Make a series of deposits and withdrawals\n",
+ "acct1.deposit(50)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Withdrawal Accepted\n"
+ ]
+ }
+ ],
+ "source": [
+ "acct1.withdraw(75)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Funds Unavailable!\n"
+ ]
+ }
+ ],
+ "source": [
+ "# 6. Make a withdrawal that exceeds the available balance\n",
+ "acct1.withdraw(500)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Good job!"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "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.6.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/06-Errors and Exception Handling/.ipynb_checkpoints/04-Unit Testing-checkpoint.ipynb b/06-Errors and Exception Handling/.ipynb_checkpoints/04-Unit Testing-checkpoint.ipynb
new file mode 100644
index 000000000..84455477d
--- /dev/null
+++ b/06-Errors and Exception Handling/.ipynb_checkpoints/04-Unit Testing-checkpoint.ipynb
@@ -0,0 +1,553 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Unit Testing\n",
+ "\n",
+ "Equally important as writing good code is writing good tests. Better to find bugs yourself than have them reported to you by end users!\n",
+ "\n",
+ "For this section we'll be working with files outside the notebook. We'll save our code to a .py file, and then save our test script to another .py file. Normally we would code these files using a text editor like Brackets or Atom, or inside an IDE like Spyder or Pycharm. But, since we're here, let's use Jupyter!\n",
+ "\n",
+ "Recall that with some IPython magic we can write the contents of a cell to a file using `%%writefile`.
\n",
+ "Something we haven't seen yet; you can run terminal commands from a jupyter cell using `!`\n",
+ "\n",
+ "## Testing tools\n",
+ "\n",
+ "There are dozens of good testing libraries out there. Most are third-party packages that require an install, such as:\n",
+ "\n",
+ "* [pylint](https://www.pylint.org/)\n",
+ "* [pyflakes](https://pypi.python.org/pypi/pyflakes/)\n",
+ "* [pep8](https://pypi.python.org/pypi/pep8)\n",
+ "\n",
+ "These are simple tools that merely look at your code, and they'll tell you if there are style issues or simple problems like variable names being called before assignment.\n",
+ "\n",
+ "A far better way to test your code is to write tests that send sample data to your program, and compare what's returned to a desired outcome.
Two such tools are available from the standard library:\n",
+ "\n",
+ "* [unittest](https://docs.python.org/3/library/unittest.html)\n",
+ "* [doctest](https://docs.python.org/3/library/doctest.html)\n",
+ "\n",
+ "Let's look at pylint first, then we'll do some heavier lifting with unittest.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## `pylint`\n",
+ "\n",
+ "`pylint` tests for style as well as some very basic program logic."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "First, if you don't have it already (and you probably do, as it's part of the Anaconda distribution), you should install `pylint`.
Once that's done feel free to comment out the cell, you won't need it anymore."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "! pip install pylint"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Let's save a very simple script:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Overwriting simple1.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile simple1.py\n",
+ "a = 1\n",
+ "b = 2\n",
+ "print(a)\n",
+ "print(B)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now let's check it using pylint"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "************* Module simple1\n",
+ "C: 4, 0: Final newline missing (missing-final-newline)\n",
+ "C: 1, 0: Missing module docstring (missing-docstring)\n",
+ "C: 1, 0: Invalid constant name \"a\" (invalid-name)\n",
+ "C: 2, 0: Invalid constant name \"b\" (invalid-name)\n",
+ "E: 4, 6: Undefined variable 'B' (undefined-variable)\n",
+ "\n",
+ "---------------------------------------------------------------------\n",
+ "\n",
+ "Your code has been rated at -12.50/10 (previous run: 8.33/10, -20.83)\n",
+ "\n",
+ "\n",
+ "\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "No config file found, using default configuration\n"
+ ]
+ }
+ ],
+ "source": [
+ "! pylint simple1.py"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Pylint first lists some styling issues - it would like to see an extra newline at the end, modules and function definitions should have descriptive docstrings, and single characters are a poor choice for variable names.\n",
+ "\n",
+ "More importantly, however, pylint identified an error in the program - a variable called before assignment. This needs fixing.\n",
+ "\n",
+ "Note that pylint scored our program a negative 12.5 out of 10. Let's try to improve that!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Overwriting simple1.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile simple1.py\n",
+ "\"\"\"\n",
+ "A very simple script.\n",
+ "\"\"\"\n",
+ "\n",
+ "def myfunc():\n",
+ " \"\"\"\n",
+ " An extremely simple function.\n",
+ " \"\"\"\n",
+ " first = 1\n",
+ " second = 2\n",
+ " print(first)\n",
+ " print(second)\n",
+ "\n",
+ "myfunc()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "************* Module simple1\n",
+ "C: 14, 0: Final newline missing (missing-final-newline)\n",
+ "\n",
+ "---------------------------------------------------------------------\n",
+ "\n",
+ "Your code has been rated at 8.33/10 (previous run: -12.50/10, +20.83)\n",
+ "\n",
+ "\n",
+ "\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "No config file found, using default configuration\n"
+ ]
+ }
+ ],
+ "source": [
+ "! pylint simple1.py"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Much better! Our score climbed to 8.33 out of 10. Unfortunately, the final newline has to do with how jupyter writes to a file, and there's not much we can do about that here. Still, pylint helped us troubleshoot some of our problems. But what if the problem was more complex?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Overwriting simple2.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile simple2.py\n",
+ "\"\"\"\n",
+ "A very simple script.\n",
+ "\"\"\"\n",
+ "\n",
+ "def myfunc():\n",
+ " \"\"\"\n",
+ " An extremely simple function.\n",
+ " \"\"\"\n",
+ " first = 1\n",
+ " second = 2\n",
+ " print(first)\n",
+ " print('second')\n",
+ "\n",
+ "myfunc()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "************* Module simple2\n",
+ "C: 14, 0: Final newline missing (missing-final-newline)\n",
+ "W: 10, 4: Unused variable 'second' (unused-variable)\n",
+ "\n",
+ "------------------------------------------------------------------\n",
+ "\n",
+ "Your code has been rated at 6.67/10 (previous run: 6.67/10, +0.00)\n",
+ "\n",
+ "\n",
+ "\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "No config file found, using default configuration\n"
+ ]
+ }
+ ],
+ "source": [
+ "! pylint simple2.py"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "pylint tells us there's an unused variable in line 10, but it doesn't know that we might get an unexpected output from line 12! For this we need a more robust set of tools. That's where `unittest` comes in."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## `unittest`\n",
+ "`unittest` lets you write your own test programs. The goal is to send a specific set of data to your program, and analyze the returned results against an expected result. \n",
+ "\n",
+ "Let's generate a simple script that capitalizes words in a given string. We'll call it **cap.py**."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Overwriting cap.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile cap.py\n",
+ "def cap_text(text):\n",
+ " return text.capitalize()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now we'll write a test script. We can call it whatever we want, but **test_cap.py** seems an obvious choice.\n",
+ "\n",
+ "When writing test functions, it's best to go from simple to complex, as each function will be run in order. Here we'll test simple, one-word strings, followed by a test of multiple word strings."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Overwriting test_cap.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile test_cap.py\n",
+ "import unittest\n",
+ "import cap\n",
+ "\n",
+ "class TestCap(unittest.TestCase):\n",
+ " \n",
+ " def test_one_word(self):\n",
+ " text = 'python'\n",
+ " result = cap.cap_text(text)\n",
+ " self.assertEqual(result, 'Python')\n",
+ " \n",
+ " def test_multiple_words(self):\n",
+ " text = 'monty python'\n",
+ " result = cap.cap_text(text)\n",
+ " self.assertEqual(result, 'Monty Python')\n",
+ " \n",
+ "if __name__ == '__main__':\n",
+ " unittest.main()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "F.\n",
+ "======================================================================\n",
+ "FAIL: test_multiple_words (__main__.TestCap)\n",
+ "----------------------------------------------------------------------\n",
+ "Traceback (most recent call last):\n",
+ " File \"test_cap.py\", line 14, in test_multiple_words\n",
+ " self.assertEqual(result, 'Monty Python')\n",
+ "AssertionError: 'Monty python' != 'Monty Python'\n",
+ "- Monty python\n",
+ "? ^\n",
+ "+ Monty Python\n",
+ "? ^\n",
+ "\n",
+ "\n",
+ "----------------------------------------------------------------------\n",
+ "Ran 2 tests in 0.000s\n",
+ "\n",
+ "FAILED (failures=1)\n"
+ ]
+ }
+ ],
+ "source": [
+ "! python test_cap.py"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "What happened? It turns out that the `.capitalize()` method only capitalizes the first letter of the first word in a string. Doing a little research on string methods, we find that `.title()` might give us what we want."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Overwriting cap.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile cap.py\n",
+ "def cap_text(text):\n",
+ " return text.title() # replace .capitalize() with .title()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "..\n",
+ "----------------------------------------------------------------------\n",
+ "Ran 2 tests in 0.000s\n",
+ "\n",
+ "OK\n"
+ ]
+ }
+ ],
+ "source": [
+ "! python test_cap.py"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Hey, it passed! But have we tested all cases? Let's add another test to **test_cap.py** to see if it handles words with apostrophes, like *don't*.\n",
+ "\n",
+ "In a text editor this would be easy, but in Jupyter we have to start from scratch."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Overwriting test_cap.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile test_cap.py\n",
+ "import unittest\n",
+ "import cap\n",
+ "\n",
+ "class TestCap(unittest.TestCase):\n",
+ " \n",
+ " def test_one_word(self):\n",
+ " text = 'python'\n",
+ " result = cap.cap_text(text)\n",
+ " self.assertEqual(result, 'Python')\n",
+ " \n",
+ " def test_multiple_words(self):\n",
+ " text = 'monty python'\n",
+ " result = cap.cap_text(text)\n",
+ " self.assertEqual(result, 'Monty Python')\n",
+ " \n",
+ " def test_with_apostrophes(self):\n",
+ " text = \"monty python's flying circus\"\n",
+ " result = cap.cap_text(text)\n",
+ " self.assertEqual(result, \"Monty Python's Flying Circus\")\n",
+ " \n",
+ "if __name__ == '__main__':\n",
+ " unittest.main()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "..F\n",
+ "======================================================================\n",
+ "FAIL: test_with_apostrophes (__main__.TestCap)\n",
+ "----------------------------------------------------------------------\n",
+ "Traceback (most recent call last):\n",
+ " File \"test_cap.py\", line 19, in test_with_apostrophes\n",
+ " self.assertEqual(result, \"Monty Python's Flying Circus\")\n",
+ "AssertionError: \"Monty Python'S Flying Circus\" != \"Monty Python's Flying Circus\"\n",
+ "- Monty Python'S Flying Circus\n",
+ "? ^\n",
+ "+ Monty Python's Flying Circus\n",
+ "? ^\n",
+ "\n",
+ "\n",
+ "----------------------------------------------------------------------\n",
+ "Ran 3 tests in 0.000s\n",
+ "\n",
+ "FAILED (failures=1)\n"
+ ]
+ }
+ ],
+ "source": [
+ "! python test_cap.py"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now we have to find a solution that handles apostrophes! There is one (look up `capwords` from the `string` module) but we'll leave that as an exercise for the reader."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Great! Now you should have a basic understanding of unit testing!"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "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.6.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/06-Errors and Exception Handling/04-Unit Testing.ipynb b/06-Errors and Exception Handling/04-Unit Testing.ipynb
new file mode 100644
index 000000000..84455477d
--- /dev/null
+++ b/06-Errors and Exception Handling/04-Unit Testing.ipynb
@@ -0,0 +1,553 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Unit Testing\n",
+ "\n",
+ "Equally important as writing good code is writing good tests. Better to find bugs yourself than have them reported to you by end users!\n",
+ "\n",
+ "For this section we'll be working with files outside the notebook. We'll save our code to a .py file, and then save our test script to another .py file. Normally we would code these files using a text editor like Brackets or Atom, or inside an IDE like Spyder or Pycharm. But, since we're here, let's use Jupyter!\n",
+ "\n",
+ "Recall that with some IPython magic we can write the contents of a cell to a file using `%%writefile`.
\n",
+ "Something we haven't seen yet; you can run terminal commands from a jupyter cell using `!`\n",
+ "\n",
+ "## Testing tools\n",
+ "\n",
+ "There are dozens of good testing libraries out there. Most are third-party packages that require an install, such as:\n",
+ "\n",
+ "* [pylint](https://www.pylint.org/)\n",
+ "* [pyflakes](https://pypi.python.org/pypi/pyflakes/)\n",
+ "* [pep8](https://pypi.python.org/pypi/pep8)\n",
+ "\n",
+ "These are simple tools that merely look at your code, and they'll tell you if there are style issues or simple problems like variable names being called before assignment.\n",
+ "\n",
+ "A far better way to test your code is to write tests that send sample data to your program, and compare what's returned to a desired outcome.
Two such tools are available from the standard library:\n",
+ "\n",
+ "* [unittest](https://docs.python.org/3/library/unittest.html)\n",
+ "* [doctest](https://docs.python.org/3/library/doctest.html)\n",
+ "\n",
+ "Let's look at pylint first, then we'll do some heavier lifting with unittest.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## `pylint`\n",
+ "\n",
+ "`pylint` tests for style as well as some very basic program logic."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "First, if you don't have it already (and you probably do, as it's part of the Anaconda distribution), you should install `pylint`.
Once that's done feel free to comment out the cell, you won't need it anymore."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "! pip install pylint"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Let's save a very simple script:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Overwriting simple1.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile simple1.py\n",
+ "a = 1\n",
+ "b = 2\n",
+ "print(a)\n",
+ "print(B)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now let's check it using pylint"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "************* Module simple1\n",
+ "C: 4, 0: Final newline missing (missing-final-newline)\n",
+ "C: 1, 0: Missing module docstring (missing-docstring)\n",
+ "C: 1, 0: Invalid constant name \"a\" (invalid-name)\n",
+ "C: 2, 0: Invalid constant name \"b\" (invalid-name)\n",
+ "E: 4, 6: Undefined variable 'B' (undefined-variable)\n",
+ "\n",
+ "---------------------------------------------------------------------\n",
+ "\n",
+ "Your code has been rated at -12.50/10 (previous run: 8.33/10, -20.83)\n",
+ "\n",
+ "\n",
+ "\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "No config file found, using default configuration\n"
+ ]
+ }
+ ],
+ "source": [
+ "! pylint simple1.py"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Pylint first lists some styling issues - it would like to see an extra newline at the end, modules and function definitions should have descriptive docstrings, and single characters are a poor choice for variable names.\n",
+ "\n",
+ "More importantly, however, pylint identified an error in the program - a variable called before assignment. This needs fixing.\n",
+ "\n",
+ "Note that pylint scored our program a negative 12.5 out of 10. Let's try to improve that!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Overwriting simple1.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile simple1.py\n",
+ "\"\"\"\n",
+ "A very simple script.\n",
+ "\"\"\"\n",
+ "\n",
+ "def myfunc():\n",
+ " \"\"\"\n",
+ " An extremely simple function.\n",
+ " \"\"\"\n",
+ " first = 1\n",
+ " second = 2\n",
+ " print(first)\n",
+ " print(second)\n",
+ "\n",
+ "myfunc()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "************* Module simple1\n",
+ "C: 14, 0: Final newline missing (missing-final-newline)\n",
+ "\n",
+ "---------------------------------------------------------------------\n",
+ "\n",
+ "Your code has been rated at 8.33/10 (previous run: -12.50/10, +20.83)\n",
+ "\n",
+ "\n",
+ "\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "No config file found, using default configuration\n"
+ ]
+ }
+ ],
+ "source": [
+ "! pylint simple1.py"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Much better! Our score climbed to 8.33 out of 10. Unfortunately, the final newline has to do with how jupyter writes to a file, and there's not much we can do about that here. Still, pylint helped us troubleshoot some of our problems. But what if the problem was more complex?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Overwriting simple2.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile simple2.py\n",
+ "\"\"\"\n",
+ "A very simple script.\n",
+ "\"\"\"\n",
+ "\n",
+ "def myfunc():\n",
+ " \"\"\"\n",
+ " An extremely simple function.\n",
+ " \"\"\"\n",
+ " first = 1\n",
+ " second = 2\n",
+ " print(first)\n",
+ " print('second')\n",
+ "\n",
+ "myfunc()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "************* Module simple2\n",
+ "C: 14, 0: Final newline missing (missing-final-newline)\n",
+ "W: 10, 4: Unused variable 'second' (unused-variable)\n",
+ "\n",
+ "------------------------------------------------------------------\n",
+ "\n",
+ "Your code has been rated at 6.67/10 (previous run: 6.67/10, +0.00)\n",
+ "\n",
+ "\n",
+ "\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "No config file found, using default configuration\n"
+ ]
+ }
+ ],
+ "source": [
+ "! pylint simple2.py"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "pylint tells us there's an unused variable in line 10, but it doesn't know that we might get an unexpected output from line 12! For this we need a more robust set of tools. That's where `unittest` comes in."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## `unittest`\n",
+ "`unittest` lets you write your own test programs. The goal is to send a specific set of data to your program, and analyze the returned results against an expected result. \n",
+ "\n",
+ "Let's generate a simple script that capitalizes words in a given string. We'll call it **cap.py**."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Overwriting cap.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile cap.py\n",
+ "def cap_text(text):\n",
+ " return text.capitalize()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now we'll write a test script. We can call it whatever we want, but **test_cap.py** seems an obvious choice.\n",
+ "\n",
+ "When writing test functions, it's best to go from simple to complex, as each function will be run in order. Here we'll test simple, one-word strings, followed by a test of multiple word strings."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Overwriting test_cap.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile test_cap.py\n",
+ "import unittest\n",
+ "import cap\n",
+ "\n",
+ "class TestCap(unittest.TestCase):\n",
+ " \n",
+ " def test_one_word(self):\n",
+ " text = 'python'\n",
+ " result = cap.cap_text(text)\n",
+ " self.assertEqual(result, 'Python')\n",
+ " \n",
+ " def test_multiple_words(self):\n",
+ " text = 'monty python'\n",
+ " result = cap.cap_text(text)\n",
+ " self.assertEqual(result, 'Monty Python')\n",
+ " \n",
+ "if __name__ == '__main__':\n",
+ " unittest.main()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "F.\n",
+ "======================================================================\n",
+ "FAIL: test_multiple_words (__main__.TestCap)\n",
+ "----------------------------------------------------------------------\n",
+ "Traceback (most recent call last):\n",
+ " File \"test_cap.py\", line 14, in test_multiple_words\n",
+ " self.assertEqual(result, 'Monty Python')\n",
+ "AssertionError: 'Monty python' != 'Monty Python'\n",
+ "- Monty python\n",
+ "? ^\n",
+ "+ Monty Python\n",
+ "? ^\n",
+ "\n",
+ "\n",
+ "----------------------------------------------------------------------\n",
+ "Ran 2 tests in 0.000s\n",
+ "\n",
+ "FAILED (failures=1)\n"
+ ]
+ }
+ ],
+ "source": [
+ "! python test_cap.py"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "What happened? It turns out that the `.capitalize()` method only capitalizes the first letter of the first word in a string. Doing a little research on string methods, we find that `.title()` might give us what we want."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Overwriting cap.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile cap.py\n",
+ "def cap_text(text):\n",
+ " return text.title() # replace .capitalize() with .title()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "..\n",
+ "----------------------------------------------------------------------\n",
+ "Ran 2 tests in 0.000s\n",
+ "\n",
+ "OK\n"
+ ]
+ }
+ ],
+ "source": [
+ "! python test_cap.py"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Hey, it passed! But have we tested all cases? Let's add another test to **test_cap.py** to see if it handles words with apostrophes, like *don't*.\n",
+ "\n",
+ "In a text editor this would be easy, but in Jupyter we have to start from scratch."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Overwriting test_cap.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile test_cap.py\n",
+ "import unittest\n",
+ "import cap\n",
+ "\n",
+ "class TestCap(unittest.TestCase):\n",
+ " \n",
+ " def test_one_word(self):\n",
+ " text = 'python'\n",
+ " result = cap.cap_text(text)\n",
+ " self.assertEqual(result, 'Python')\n",
+ " \n",
+ " def test_multiple_words(self):\n",
+ " text = 'monty python'\n",
+ " result = cap.cap_text(text)\n",
+ " self.assertEqual(result, 'Monty Python')\n",
+ " \n",
+ " def test_with_apostrophes(self):\n",
+ " text = \"monty python's flying circus\"\n",
+ " result = cap.cap_text(text)\n",
+ " self.assertEqual(result, \"Monty Python's Flying Circus\")\n",
+ " \n",
+ "if __name__ == '__main__':\n",
+ " unittest.main()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "..F\n",
+ "======================================================================\n",
+ "FAIL: test_with_apostrophes (__main__.TestCap)\n",
+ "----------------------------------------------------------------------\n",
+ "Traceback (most recent call last):\n",
+ " File \"test_cap.py\", line 19, in test_with_apostrophes\n",
+ " self.assertEqual(result, \"Monty Python's Flying Circus\")\n",
+ "AssertionError: \"Monty Python'S Flying Circus\" != \"Monty Python's Flying Circus\"\n",
+ "- Monty Python'S Flying Circus\n",
+ "? ^\n",
+ "+ Monty Python's Flying Circus\n",
+ "? ^\n",
+ "\n",
+ "\n",
+ "----------------------------------------------------------------------\n",
+ "Ran 3 tests in 0.000s\n",
+ "\n",
+ "FAILED (failures=1)\n"
+ ]
+ }
+ ],
+ "source": [
+ "! python test_cap.py"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now we have to find a solution that handles apostrophes! There is one (look up `capwords` from the `string` module) but we'll leave that as an exercise for the reader."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Great! Now you should have a basic understanding of unit testing!"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "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.6.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/06-Errors and Exception Handling/__pycache__/cap.cpython-36.pyc b/06-Errors and Exception Handling/__pycache__/cap.cpython-36.pyc
new file mode 100644
index 000000000..5dc144f89
Binary files /dev/null and b/06-Errors and Exception Handling/__pycache__/cap.cpython-36.pyc differ
diff --git a/06-Errors and Exception Handling/cap.py b/06-Errors and Exception Handling/cap.py
new file mode 100644
index 000000000..6f0a9db7e
--- /dev/null
+++ b/06-Errors and Exception Handling/cap.py
@@ -0,0 +1,2 @@
+def cap_text(text):
+ return text.title() # replace .capitalize() with .title()
\ No newline at end of file
diff --git a/06-Errors and Exception Handling/simple1.py b/06-Errors and Exception Handling/simple1.py
new file mode 100644
index 000000000..ccc2100aa
--- /dev/null
+++ b/06-Errors and Exception Handling/simple1.py
@@ -0,0 +1,14 @@
+"""
+A very simple script.
+"""
+
+def myfunc():
+ """
+ An extremely simple function.
+ """
+ first = 1
+ second = 2
+ print(first)
+ print(second)
+
+myfunc()
\ No newline at end of file
diff --git a/06-Errors and Exception Handling/simple2.py b/06-Errors and Exception Handling/simple2.py
new file mode 100644
index 000000000..269ac815b
--- /dev/null
+++ b/06-Errors and Exception Handling/simple2.py
@@ -0,0 +1,14 @@
+"""
+A very simple script.
+"""
+
+def myfunc():
+ """
+ An extremely simple function.
+ """
+ first = 1
+ second = 2
+ print(first)
+ print('second')
+
+myfunc()
\ No newline at end of file
diff --git a/06-Errors and Exception Handling/test_cap.py b/06-Errors and Exception Handling/test_cap.py
new file mode 100644
index 000000000..467aaab3d
--- /dev/null
+++ b/06-Errors and Exception Handling/test_cap.py
@@ -0,0 +1,22 @@
+import unittest
+import cap
+
+class TestCap(unittest.TestCase):
+
+ def test_one_word(self):
+ text = 'python'
+ result = cap.cap_text(text)
+ self.assertEqual(result, 'Python')
+
+ def test_multiple_words(self):
+ text = 'monty python'
+ result = cap.cap_text(text)
+ self.assertEqual(result, 'Monty Python')
+
+ def test_with_apostrophes(self):
+ text = "monty python's flying circus"
+ result = cap.cap_text(text)
+ self.assertEqual(result, "Monty Python's Flying Circus")
+
+if __name__ == '__main__':
+ unittest.main()
\ No newline at end of file
diff --git a/17-Parallel Processing/.ipynb_checkpoints/01-Multithreading and Multiprocessing-checkpoint.ipynb b/17-Parallel Processing/.ipynb_checkpoints/01-Multithreading and Multiprocessing-checkpoint.ipynb
new file mode 100644
index 000000000..b7550a416
--- /dev/null
+++ b/17-Parallel Processing/.ipynb_checkpoints/01-Multithreading and Multiprocessing-checkpoint.ipynb
@@ -0,0 +1,552 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Multithreading and Multiprocessing\n",
+ "\n",
+ "Recall the phrase \"many hands make light work\". This is as true in programming as anywhere else.\n",
+ "\n",
+ "What if you could engineer your Python program to do four things at once? What would normally take an hour could (almost) take one fourth the time.\\*\n",
+ "\n",
+ "This is the idea behind parallel processing, or the ability to set up and run multiple tasks concurrently.\n",
+ "\n",
+ "\n",
+ "
\\* *We say almost, because you do have to take time setting up four processors, and it may take time to pass information between them.*"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Threading vs. Processing\n",
+ "\n",
+ "A good illustration of threading vs. processing would be to download an image file and turn it into a thumbnail.\n",
+ "\n",
+ "The first part, communicating with an outside source to download a file, involves a thread. Once the file is obtained, the work of converting it involves a process. Essentially, two factors determine how long this will take; the input/output speed of the network communication, or I/O, and the available processor, or CPU.\n",
+ "\n",
+ "#### I/O-intensive processes improved with multithreading:\n",
+ "* webscraping\n",
+ "* reading and writing to files\n",
+ "* sharing data between programs\n",
+ "* network communications\n",
+ "\n",
+ "\n",
+ "#### CPU-intensive processes improved with multiprocessing:\n",
+ "* computations\n",
+ "* text formatting\n",
+ "* image rescaling\n",
+ "* data analysis"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Multithreading Example: Webscraping\n",
+ "\n",
+ "Historically, the programming knowledge required to set up multithreading was beyond the scope of this course, as it involved a good understanding of Python's Global Interpreter Lock (the GIL prevents multiple threads from running the same Python code at once). Also, you had to set up special classes that behave like Producers to divvy up the work, Consumers (aka \"workers\") to perform the work, and a Queue to hold tasks and provide communcations. And that was just the beginning.\n",
+ "\n",
+ "Fortunately, we've already learned one of the most valuable tools we'll need – the `map()` function. When we apply it using two standard libraries, *multiprocessing* and *multiprocessing.dummy*, setting up parallel processes and threads becomes fairly straightforward.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Here's a classic multithreading example provided by [IBM](http://www.ibm.com/developerworks/aix/library/au-threadingpython/) and adapted by [Chris Kiehl](http://chriskiehl.com/article/parallelism-in-one-line/) where you divide the task of retrieving web pages across multiple threads:\n",
+ "\n",
+ "\n",
+ " import time \n",
+ " import threading \n",
+ " import Queue \n",
+ " import urllib2 \n",
+ "\n",
+ " class Consumer(threading.Thread): \n",
+ " def __init__(self, queue): \n",
+ " threading.Thread.__init__(self)\n",
+ " self._queue = queue \n",
+ "\n",
+ " def run(self):\n",
+ " while True: \n",
+ " content = self._queue.get() \n",
+ " if isinstance(content, str) and content == 'quit':\n",
+ " break\n",
+ " response = urllib2.urlopen(content)\n",
+ " print 'Thanks!'\n",
+ "\n",
+ "\n",
+ " def Producer():\n",
+ " urls = [\n",
+ " 'http://www.python.org', 'http://www.yahoo.com'\n",
+ " 'http://www.scala.org', 'http://www.google.com'\n",
+ " # etc.. \n",
+ " ]\n",
+ " queue = Queue.Queue()\n",
+ " worker_threads = build_worker_pool(queue, 4)\n",
+ " start_time = time.time()\n",
+ "\n",
+ " # Add the urls to process\n",
+ " for url in urls: \n",
+ " queue.put(url) \n",
+ " # Add the poison pill\n",
+ " for worker in worker_threads:\n",
+ " queue.put('quit')\n",
+ " for worker in worker_threads:\n",
+ " worker.join()\n",
+ "\n",
+ " print 'Done! Time taken: {}'.format(time.time() - start_time)\n",
+ "\n",
+ " def build_worker_pool(queue, size):\n",
+ " workers = []\n",
+ " for _ in range(size):\n",
+ " worker = Consumer(queue)\n",
+ " worker.start() \n",
+ " workers.append(worker)\n",
+ " return workers\n",
+ "\n",
+ " if __name__ == '__main__':\n",
+ " Producer()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Using the multithreading library provided by the *multiprocessing.dummy* module and `map()` all of this becomes:\n",
+ "\n",
+ " import urllib2\n",
+ " from multiprocessing.dummy import Pool as ThreadPool\n",
+ " \n",
+ " pool = ThreadPool(4) # choose a number of workers\n",
+ " \n",
+ " urls = [\n",
+ " 'http://www.python.org', 'http://www.yahoo.com'\n",
+ " 'http://www.scala.org', 'http://www.google.com'\n",
+ " # etc.. \n",
+ " ]\n",
+ " \n",
+ " results = pool.map(urllib2.urlopen, urls)\n",
+ " pool.close() \n",
+ " pool.join()\n",
+ " \n",
+ "In the above code, the *multiprocessing.dummy* module provides the parallel threads, and `map(urllib2.urlopen, urls)` assigns the labor!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Multiprocessing Example: Monte Carlo\n",
+ "\n",
+ "Let's code out an example to see how the parts fit together. We can time our results using the *timeit* module to measure any performance gains. Our task is to apply the Monte Carlo Method to estimate the value of Pi."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Monte Carle Method and Estimating Pi\n",
+ "\n",
+ "If you draw a circle of radius 1 (a unit circle) and enclose it in a square, the areas of the two shapes are given as\n",
+ "\n",
+ "
\n",
+ " Area Formulas\n",
+ " circle | $$πr^2$$ |
\n",
+ " square | $$4 r^2$$ |
\n",
+ "
\n",
+ "\n",
+ "\n",
+ "Therefore, the ratio of the volume of the circle to the volume of the square is $$\\frac{π}{4}$$\n",
+ "\n",
+ "The Monte Carlo Method plots a series of random points inside the square. By comparing the number that fall within the circle to those that fall outside, with a large enough sample we should have a good approximation of Pi. You can see a good demonstration of this [here](https://academo.org/demos/estimating-pi-monte-carlo/) (Hit the **Animate** button on the page).\n",
+ "\n",
+ "For a given number of points *n*, we have $$π = \\frac{4 \\cdot points\\ inside\\ circle}{total\\ points\\ n}$$\n",
+ "\n",
+ "To set up our multiprocessing program, we first derive a function for finding Pi that we can pass to `map()`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from random import random # perform this import outside the function\n",
+ "\n",
+ "def find_pi(n):\n",
+ " \"\"\"\n",
+ " Function to estimate the value of Pi\n",
+ " \"\"\"\n",
+ " inside=0\n",
+ "\n",
+ " for i in range(0,n):\n",
+ " x=random()\n",
+ " y=random()\n",
+ " if (x*x+y*y)**(0.5)<=1: # if i falls inside the circle\n",
+ " inside+=1\n",
+ "\n",
+ " pi=4*inside/n\n",
+ " return pi"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Let's test `find_pi` on 5,000 points:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "3.1064"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "find_pi(5000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This ran very quickly, but the results are not very accurate!\n",
+ "\n",
+ "Next we'll write a script that sets up a pool of workers, and lets us time the results against varying sized pools. We'll set up two arguments to represent *processes* and *total_iterations*. Inside the script, we'll break *total_iterations* down into the number of iterations passed to each process, by making a processes-sized list.
For example:\n",
+ "\n",
+ " total_iterations = 1000\n",
+ " processes = 5\n",
+ " iterations = [total_iterations//processes]*processes\n",
+ " iterations\n",
+ " # Output: [200, 200, 200, 200, 200]\n",
+ " \n",
+ "This list will be passed to our `map()` function along with `find_pi()`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Writing test.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile test.py\n",
+ "from random import random\n",
+ "from multiprocessing import Pool\n",
+ "import timeit\n",
+ "\n",
+ "def find_pi(n):\n",
+ " \"\"\"\n",
+ " Function to estimate the value of Pi\n",
+ " \"\"\"\n",
+ " inside=0\n",
+ "\n",
+ " for i in range(0,n):\n",
+ " x=random()\n",
+ " y=random()\n",
+ " if (x*x+y*y)**(0.5)<=1: # if i falls inside the circle\n",
+ " inside+=1\n",
+ "\n",
+ " pi=4*inside/n\n",
+ " return pi\n",
+ "\n",
+ "if __name__ == '__main__':\n",
+ " N = 10**5 # total iterations\n",
+ " P = 5 # number of processes\n",
+ " \n",
+ " p = Pool(P)\n",
+ " print(timeit.timeit(lambda: print(f'{sum(p.map(find_pi, [N//P]*P))/P:0.7f}'), number=10))\n",
+ " p.close()\n",
+ " p.join()\n",
+ " print(f'{N} total iterations with {P} processes')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "3.1466800\n",
+ "3.1364400\n",
+ "3.1470400\n",
+ "3.1370400\n",
+ "3.1256400\n",
+ "3.1398400\n",
+ "3.1395200\n",
+ "3.1363600\n",
+ "3.1437200\n",
+ "3.1334400\n",
+ "0.2370227286270967\n",
+ "100000 total iterations with 5 processes\n"
+ ]
+ }
+ ],
+ "source": [
+ "! python test.py"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Great! The above test took under a second on our computer.\n",
+ "\n",
+ "Now that we know our script works, let's increase the number of iterations, and compare two different pools. Sit back, this may take awhile!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Overwriting test.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile test.py\n",
+ "from random import random\n",
+ "from multiprocessing import Pool\n",
+ "import timeit\n",
+ "\n",
+ "def find_pi(n):\n",
+ " \"\"\"\n",
+ " Function to estimate the value of Pi\n",
+ " \"\"\"\n",
+ " inside=0\n",
+ "\n",
+ " for i in range(0,n):\n",
+ " x=random()\n",
+ " y=random()\n",
+ " if (x*x+y*y)**(0.5)<=1: # if i falls inside the circle\n",
+ " inside+=1\n",
+ "\n",
+ " pi=4*inside/n\n",
+ " return pi\n",
+ "\n",
+ "if __name__ == '__main__':\n",
+ " N = 10**7 # total iterations\n",
+ " \n",
+ " P = 1 # number of processes\n",
+ " p = Pool(P)\n",
+ " print(timeit.timeit(lambda: print(f'{sum(p.map(find_pi, [N//P]*P))/P:0.7f}'), number=10))\n",
+ " p.close()\n",
+ " p.join()\n",
+ " print(f'{N} total iterations with {P} processes')\n",
+ " \n",
+ " P = 5 # number of processes\n",
+ " p = Pool(P)\n",
+ " print(timeit.timeit(lambda: print(f'{sum(p.map(find_pi, [N//P]*P))/P:0.7f}'), number=10))\n",
+ " p.close()\n",
+ " p.join()\n",
+ " print(f'{N} total iterations with {P} processes')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "3.1420964\n",
+ "3.1417412\n",
+ "3.1411108\n",
+ "3.1408184\n",
+ "3.1414204\n",
+ "3.1417656\n",
+ "3.1408324\n",
+ "3.1418828\n",
+ "3.1420492\n",
+ "3.1412804\n",
+ "36.03526345242264\n",
+ "10000000 total iterations with 1 processes\n",
+ "3.1424524\n",
+ "3.1418376\n",
+ "3.1415292\n",
+ "3.1410344\n",
+ "3.1422376\n",
+ "3.1418736\n",
+ "3.1420540\n",
+ "3.1411452\n",
+ "3.1421652\n",
+ "3.1410672\n",
+ "17.300921846344366\n",
+ "10000000 total iterations with 5 processes\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "! python test.py"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Hopefully you saw that with 5 processes our script ran faster!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## More is Better ...to a point.\n",
+ "\n",
+ "The gain in speed as you add more parallel processes tends to flatten out at some point. In any collection of tasks, there are going to be one or two that take longer than average, and no amount of added processing can speed them up. This is best described in [Amdahl's Law](https://en.wikipedia.org/wiki/Amdahl%27s_law)."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Advanced Script\n",
+ "\n",
+ "In the example below, we'll add a context manager to shrink these three lines\n",
+ "\n",
+ " p = Pool(P)\n",
+ " ...\n",
+ " p.close()\n",
+ " p.join()\n",
+ " \n",
+ "to one line:\n",
+ "\n",
+ " with Pool(P) as p:\n",
+ " \n",
+ "And we'll accept command line arguments using the *sys* module.\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Writing test2.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile test2.py\n",
+ "from random import random\n",
+ "from multiprocessing import Pool\n",
+ "import timeit\n",
+ "import sys\n",
+ "\n",
+ "N = int(sys.argv[1]) # these arguments are passed in from the command line\n",
+ "P = int(sys.argv[2])\n",
+ "\n",
+ "def find_pi(n):\n",
+ " \"\"\"\n",
+ " Function to estimate the value of Pi\n",
+ " \"\"\"\n",
+ " inside=0\n",
+ "\n",
+ " for i in range(0,n):\n",
+ " x=random()\n",
+ " y=random()\n",
+ " if (x*x+y*y)**(0.5)<=1: # if i falls inside the circle\n",
+ " inside+=1\n",
+ "\n",
+ " pi=4*inside/n\n",
+ " return pi\n",
+ "\n",
+ "if __name__ == '__main__':\n",
+ " \n",
+ " with Pool(P) as p:\n",
+ " print(timeit.timeit(lambda: print(f'{sum(p.map(find_pi, [N//P]*P))/P:0.5f}'), number=10))\n",
+ " print(f'{N} total iterations with {P} processes')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "3.14121\n",
+ "3.14145\n",
+ "3.14178\n",
+ "3.14194\n",
+ "3.14109\n",
+ "3.14201\n",
+ "3.14243\n",
+ "3.14150\n",
+ "3.14203\n",
+ "3.14116\n",
+ "16.871822701405073\n",
+ "10000000 total iterations with 500 processes\n"
+ ]
+ }
+ ],
+ "source": [
+ "! python test2.py 10000000 500"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Great! Now you should have a good understanding of multithreading and multiprocessing!"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "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.6.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/17-Parallel Processing/01-Multithreading and Multiprocessing.ipynb b/17-Parallel Processing/01-Multithreading and Multiprocessing.ipynb
new file mode 100644
index 000000000..b7550a416
--- /dev/null
+++ b/17-Parallel Processing/01-Multithreading and Multiprocessing.ipynb
@@ -0,0 +1,552 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Multithreading and Multiprocessing\n",
+ "\n",
+ "Recall the phrase \"many hands make light work\". This is as true in programming as anywhere else.\n",
+ "\n",
+ "What if you could engineer your Python program to do four things at once? What would normally take an hour could (almost) take one fourth the time.\\*\n",
+ "\n",
+ "This is the idea behind parallel processing, or the ability to set up and run multiple tasks concurrently.\n",
+ "\n",
+ "\n",
+ "
\\* *We say almost, because you do have to take time setting up four processors, and it may take time to pass information between them.*"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Threading vs. Processing\n",
+ "\n",
+ "A good illustration of threading vs. processing would be to download an image file and turn it into a thumbnail.\n",
+ "\n",
+ "The first part, communicating with an outside source to download a file, involves a thread. Once the file is obtained, the work of converting it involves a process. Essentially, two factors determine how long this will take; the input/output speed of the network communication, or I/O, and the available processor, or CPU.\n",
+ "\n",
+ "#### I/O-intensive processes improved with multithreading:\n",
+ "* webscraping\n",
+ "* reading and writing to files\n",
+ "* sharing data between programs\n",
+ "* network communications\n",
+ "\n",
+ "\n",
+ "#### CPU-intensive processes improved with multiprocessing:\n",
+ "* computations\n",
+ "* text formatting\n",
+ "* image rescaling\n",
+ "* data analysis"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Multithreading Example: Webscraping\n",
+ "\n",
+ "Historically, the programming knowledge required to set up multithreading was beyond the scope of this course, as it involved a good understanding of Python's Global Interpreter Lock (the GIL prevents multiple threads from running the same Python code at once). Also, you had to set up special classes that behave like Producers to divvy up the work, Consumers (aka \"workers\") to perform the work, and a Queue to hold tasks and provide communcations. And that was just the beginning.\n",
+ "\n",
+ "Fortunately, we've already learned one of the most valuable tools we'll need – the `map()` function. When we apply it using two standard libraries, *multiprocessing* and *multiprocessing.dummy*, setting up parallel processes and threads becomes fairly straightforward.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Here's a classic multithreading example provided by [IBM](http://www.ibm.com/developerworks/aix/library/au-threadingpython/) and adapted by [Chris Kiehl](http://chriskiehl.com/article/parallelism-in-one-line/) where you divide the task of retrieving web pages across multiple threads:\n",
+ "\n",
+ "\n",
+ " import time \n",
+ " import threading \n",
+ " import Queue \n",
+ " import urllib2 \n",
+ "\n",
+ " class Consumer(threading.Thread): \n",
+ " def __init__(self, queue): \n",
+ " threading.Thread.__init__(self)\n",
+ " self._queue = queue \n",
+ "\n",
+ " def run(self):\n",
+ " while True: \n",
+ " content = self._queue.get() \n",
+ " if isinstance(content, str) and content == 'quit':\n",
+ " break\n",
+ " response = urllib2.urlopen(content)\n",
+ " print 'Thanks!'\n",
+ "\n",
+ "\n",
+ " def Producer():\n",
+ " urls = [\n",
+ " 'http://www.python.org', 'http://www.yahoo.com'\n",
+ " 'http://www.scala.org', 'http://www.google.com'\n",
+ " # etc.. \n",
+ " ]\n",
+ " queue = Queue.Queue()\n",
+ " worker_threads = build_worker_pool(queue, 4)\n",
+ " start_time = time.time()\n",
+ "\n",
+ " # Add the urls to process\n",
+ " for url in urls: \n",
+ " queue.put(url) \n",
+ " # Add the poison pill\n",
+ " for worker in worker_threads:\n",
+ " queue.put('quit')\n",
+ " for worker in worker_threads:\n",
+ " worker.join()\n",
+ "\n",
+ " print 'Done! Time taken: {}'.format(time.time() - start_time)\n",
+ "\n",
+ " def build_worker_pool(queue, size):\n",
+ " workers = []\n",
+ " for _ in range(size):\n",
+ " worker = Consumer(queue)\n",
+ " worker.start() \n",
+ " workers.append(worker)\n",
+ " return workers\n",
+ "\n",
+ " if __name__ == '__main__':\n",
+ " Producer()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Using the multithreading library provided by the *multiprocessing.dummy* module and `map()` all of this becomes:\n",
+ "\n",
+ " import urllib2\n",
+ " from multiprocessing.dummy import Pool as ThreadPool\n",
+ " \n",
+ " pool = ThreadPool(4) # choose a number of workers\n",
+ " \n",
+ " urls = [\n",
+ " 'http://www.python.org', 'http://www.yahoo.com'\n",
+ " 'http://www.scala.org', 'http://www.google.com'\n",
+ " # etc.. \n",
+ " ]\n",
+ " \n",
+ " results = pool.map(urllib2.urlopen, urls)\n",
+ " pool.close() \n",
+ " pool.join()\n",
+ " \n",
+ "In the above code, the *multiprocessing.dummy* module provides the parallel threads, and `map(urllib2.urlopen, urls)` assigns the labor!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Multiprocessing Example: Monte Carlo\n",
+ "\n",
+ "Let's code out an example to see how the parts fit together. We can time our results using the *timeit* module to measure any performance gains. Our task is to apply the Monte Carlo Method to estimate the value of Pi."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Monte Carle Method and Estimating Pi\n",
+ "\n",
+ "If you draw a circle of radius 1 (a unit circle) and enclose it in a square, the areas of the two shapes are given as\n",
+ "\n",
+ "\n",
+ " Area Formulas\n",
+ " circle | $$πr^2$$ |
\n",
+ " square | $$4 r^2$$ |
\n",
+ "
\n",
+ "\n",
+ "\n",
+ "Therefore, the ratio of the volume of the circle to the volume of the square is $$\\frac{π}{4}$$\n",
+ "\n",
+ "The Monte Carlo Method plots a series of random points inside the square. By comparing the number that fall within the circle to those that fall outside, with a large enough sample we should have a good approximation of Pi. You can see a good demonstration of this [here](https://academo.org/demos/estimating-pi-monte-carlo/) (Hit the **Animate** button on the page).\n",
+ "\n",
+ "For a given number of points *n*, we have $$π = \\frac{4 \\cdot points\\ inside\\ circle}{total\\ points\\ n}$$\n",
+ "\n",
+ "To set up our multiprocessing program, we first derive a function for finding Pi that we can pass to `map()`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from random import random # perform this import outside the function\n",
+ "\n",
+ "def find_pi(n):\n",
+ " \"\"\"\n",
+ " Function to estimate the value of Pi\n",
+ " \"\"\"\n",
+ " inside=0\n",
+ "\n",
+ " for i in range(0,n):\n",
+ " x=random()\n",
+ " y=random()\n",
+ " if (x*x+y*y)**(0.5)<=1: # if i falls inside the circle\n",
+ " inside+=1\n",
+ "\n",
+ " pi=4*inside/n\n",
+ " return pi"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Let's test `find_pi` on 5,000 points:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "3.1064"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "find_pi(5000)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This ran very quickly, but the results are not very accurate!\n",
+ "\n",
+ "Next we'll write a script that sets up a pool of workers, and lets us time the results against varying sized pools. We'll set up two arguments to represent *processes* and *total_iterations*. Inside the script, we'll break *total_iterations* down into the number of iterations passed to each process, by making a processes-sized list.
For example:\n",
+ "\n",
+ " total_iterations = 1000\n",
+ " processes = 5\n",
+ " iterations = [total_iterations//processes]*processes\n",
+ " iterations\n",
+ " # Output: [200, 200, 200, 200, 200]\n",
+ " \n",
+ "This list will be passed to our `map()` function along with `find_pi()`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Writing test.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile test.py\n",
+ "from random import random\n",
+ "from multiprocessing import Pool\n",
+ "import timeit\n",
+ "\n",
+ "def find_pi(n):\n",
+ " \"\"\"\n",
+ " Function to estimate the value of Pi\n",
+ " \"\"\"\n",
+ " inside=0\n",
+ "\n",
+ " for i in range(0,n):\n",
+ " x=random()\n",
+ " y=random()\n",
+ " if (x*x+y*y)**(0.5)<=1: # if i falls inside the circle\n",
+ " inside+=1\n",
+ "\n",
+ " pi=4*inside/n\n",
+ " return pi\n",
+ "\n",
+ "if __name__ == '__main__':\n",
+ " N = 10**5 # total iterations\n",
+ " P = 5 # number of processes\n",
+ " \n",
+ " p = Pool(P)\n",
+ " print(timeit.timeit(lambda: print(f'{sum(p.map(find_pi, [N//P]*P))/P:0.7f}'), number=10))\n",
+ " p.close()\n",
+ " p.join()\n",
+ " print(f'{N} total iterations with {P} processes')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "3.1466800\n",
+ "3.1364400\n",
+ "3.1470400\n",
+ "3.1370400\n",
+ "3.1256400\n",
+ "3.1398400\n",
+ "3.1395200\n",
+ "3.1363600\n",
+ "3.1437200\n",
+ "3.1334400\n",
+ "0.2370227286270967\n",
+ "100000 total iterations with 5 processes\n"
+ ]
+ }
+ ],
+ "source": [
+ "! python test.py"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Great! The above test took under a second on our computer.\n",
+ "\n",
+ "Now that we know our script works, let's increase the number of iterations, and compare two different pools. Sit back, this may take awhile!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Overwriting test.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile test.py\n",
+ "from random import random\n",
+ "from multiprocessing import Pool\n",
+ "import timeit\n",
+ "\n",
+ "def find_pi(n):\n",
+ " \"\"\"\n",
+ " Function to estimate the value of Pi\n",
+ " \"\"\"\n",
+ " inside=0\n",
+ "\n",
+ " for i in range(0,n):\n",
+ " x=random()\n",
+ " y=random()\n",
+ " if (x*x+y*y)**(0.5)<=1: # if i falls inside the circle\n",
+ " inside+=1\n",
+ "\n",
+ " pi=4*inside/n\n",
+ " return pi\n",
+ "\n",
+ "if __name__ == '__main__':\n",
+ " N = 10**7 # total iterations\n",
+ " \n",
+ " P = 1 # number of processes\n",
+ " p = Pool(P)\n",
+ " print(timeit.timeit(lambda: print(f'{sum(p.map(find_pi, [N//P]*P))/P:0.7f}'), number=10))\n",
+ " p.close()\n",
+ " p.join()\n",
+ " print(f'{N} total iterations with {P} processes')\n",
+ " \n",
+ " P = 5 # number of processes\n",
+ " p = Pool(P)\n",
+ " print(timeit.timeit(lambda: print(f'{sum(p.map(find_pi, [N//P]*P))/P:0.7f}'), number=10))\n",
+ " p.close()\n",
+ " p.join()\n",
+ " print(f'{N} total iterations with {P} processes')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "3.1420964\n",
+ "3.1417412\n",
+ "3.1411108\n",
+ "3.1408184\n",
+ "3.1414204\n",
+ "3.1417656\n",
+ "3.1408324\n",
+ "3.1418828\n",
+ "3.1420492\n",
+ "3.1412804\n",
+ "36.03526345242264\n",
+ "10000000 total iterations with 1 processes\n",
+ "3.1424524\n",
+ "3.1418376\n",
+ "3.1415292\n",
+ "3.1410344\n",
+ "3.1422376\n",
+ "3.1418736\n",
+ "3.1420540\n",
+ "3.1411452\n",
+ "3.1421652\n",
+ "3.1410672\n",
+ "17.300921846344366\n",
+ "10000000 total iterations with 5 processes\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "! python test.py"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Hopefully you saw that with 5 processes our script ran faster!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## More is Better ...to a point.\n",
+ "\n",
+ "The gain in speed as you add more parallel processes tends to flatten out at some point. In any collection of tasks, there are going to be one or two that take longer than average, and no amount of added processing can speed them up. This is best described in [Amdahl's Law](https://en.wikipedia.org/wiki/Amdahl%27s_law)."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Advanced Script\n",
+ "\n",
+ "In the example below, we'll add a context manager to shrink these three lines\n",
+ "\n",
+ " p = Pool(P)\n",
+ " ...\n",
+ " p.close()\n",
+ " p.join()\n",
+ " \n",
+ "to one line:\n",
+ "\n",
+ " with Pool(P) as p:\n",
+ " \n",
+ "And we'll accept command line arguments using the *sys* module.\n",
+ " "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Writing test2.py\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile test2.py\n",
+ "from random import random\n",
+ "from multiprocessing import Pool\n",
+ "import timeit\n",
+ "import sys\n",
+ "\n",
+ "N = int(sys.argv[1]) # these arguments are passed in from the command line\n",
+ "P = int(sys.argv[2])\n",
+ "\n",
+ "def find_pi(n):\n",
+ " \"\"\"\n",
+ " Function to estimate the value of Pi\n",
+ " \"\"\"\n",
+ " inside=0\n",
+ "\n",
+ " for i in range(0,n):\n",
+ " x=random()\n",
+ " y=random()\n",
+ " if (x*x+y*y)**(0.5)<=1: # if i falls inside the circle\n",
+ " inside+=1\n",
+ "\n",
+ " pi=4*inside/n\n",
+ " return pi\n",
+ "\n",
+ "if __name__ == '__main__':\n",
+ " \n",
+ " with Pool(P) as p:\n",
+ " print(timeit.timeit(lambda: print(f'{sum(p.map(find_pi, [N//P]*P))/P:0.5f}'), number=10))\n",
+ " print(f'{N} total iterations with {P} processes')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "3.14121\n",
+ "3.14145\n",
+ "3.14178\n",
+ "3.14194\n",
+ "3.14109\n",
+ "3.14201\n",
+ "3.14243\n",
+ "3.14150\n",
+ "3.14203\n",
+ "3.14116\n",
+ "16.871822701405073\n",
+ "10000000 total iterations with 500 processes\n"
+ ]
+ }
+ ],
+ "source": [
+ "! python test2.py 10000000 500"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Great! Now you should have a good understanding of multithreading and multiprocessing!"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "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.6.2"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/17-Parallel Processing/test.py b/17-Parallel Processing/test.py
new file mode 100644
index 000000000..a75551c5a
--- /dev/null
+++ b/17-Parallel Processing/test.py
@@ -0,0 +1,35 @@
+from random import random
+from multiprocessing import Pool
+import timeit
+
+def find_pi(n):
+ """
+ Function to estimate the value of Pi
+ """
+ inside=0
+
+ for i in range(0,n):
+ x=random()
+ y=random()
+ if (x*x+y*y)**(0.5)<=1: # if i falls inside the circle
+ inside+=1
+
+ pi=4*inside/n
+ return pi
+
+if __name__ == '__main__':
+ N = 10**7 # total iterations
+
+ P = 1 # number of processes
+ p = Pool(P)
+ print(timeit.timeit(lambda: print(f'{sum(p.map(find_pi, [N//P]*P))/P:0.7f}'), number=10))
+ p.close()
+ p.join()
+ print(f'{N} total iterations with {P} processes')
+
+ P = 5 # number of processes
+ p = Pool(P)
+ print(timeit.timeit(lambda: print(f'{sum(p.map(find_pi, [N//P]*P))/P:0.7f}'), number=10))
+ p.close()
+ p.join()
+ print(f'{N} total iterations with {P} processes\n')
\ No newline at end of file
diff --git a/17-Parallel Processing/test2.py b/17-Parallel Processing/test2.py
new file mode 100644
index 000000000..15d87c26a
--- /dev/null
+++ b/17-Parallel Processing/test2.py
@@ -0,0 +1,28 @@
+from random import random
+from multiprocessing import Pool
+import timeit
+import sys
+
+N = int(sys.argv[1]) # these arguments are passed in from the command line
+P = int(sys.argv[2])
+
+def find_pi(n):
+ """
+ Function to estimate the value of Pi
+ """
+ inside=0
+
+ for i in range(0,n):
+ x=random()
+ y=random()
+ if (x*x+y*y)**(0.5)<=1: # if i falls inside the circle
+ inside+=1
+
+ pi=4*inside/n
+ return pi
+
+if __name__ == '__main__':
+
+ with Pool(P) as p:
+ print(timeit.timeit(lambda: print(f'{sum(p.map(find_pi, [N//P]*P))/P:0.5f}'), number=10))
+ print(f'{N} total iterations with {P} processes')
\ No newline at end of file
diff --git a/MultiProcessing.ipynb b/MultiProcessing.ipynb
deleted file mode 100644
index d4218415a..000000000
--- a/MultiProcessing.ipynb
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": []
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 2",
- "language": "python",
- "name": "python2"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 2
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython2",
- "version": "2.7.10"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}