{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# User-Defined Functions: Advanced Topics" ] }, { "cell_type": "markdown", "metadata": { "heading_collapsed": true }, "source": [ "## Meal Example, and default values for parameters" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "#TODO (Advanced): Introduce the notion of adding default values\n", "def meal_cost(food_cost, tax_rate=8.875, tip_perc=15):\n", " total_cost = food_cost + food_cost * (tax_rate/100) + food_cost * (tip_perc/100)\n", " total_cost = round(total_cost,2)\n", " return total_cost" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "food = 50\n", "cost = meal_cost(food)\n", "print(f\"The cost of the meal will be: ${cost}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "food = 50\n", "tax = 8.875\n", "tip = 15\n", "cost = meal_cost(food, tax, tip)\n", "print(f\"The cost of the meal will be: ${cost}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "food = 50\n", "tax = 8.875\n", "cost = meal_cost(food, tax)\n", "print(f\"The cost of the meal will be: ${cost}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "food = 50\n", "tip = 20\n", "# THIS DOES NOT WORK. COMPARE WITH THE CODE BELOW\n", "# IF WE HAVE TWO PARAMETERS THE SECOND ONE IS ASSUMED TO BE TAX, NOT TIP \n", "cost = meal_cost(food, tip)\n", "print(f\"The cost of the meal will be: ${cost}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Meal Example, and calling the `name=value` convention for the parameter" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "food = 50\n", "tax = 8.875\n", "tip = 20\n", "cost = meal_cost(food, tax, tip)\n", "print(f\"The cost of the meal will be: ${cost}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#TODO: Introduce the notion of calling by naming the parameters\n", "cost = meal_cost(food_cost=30, tax_rate=8.875, tip_perc=15)\n", "print(f\"The cost of the meal will be: ${cost}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Returning multiple values: Examples with length of text in characters, words, sentences\n", "\n", "* Return tuple\n", "* Return dictionary" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example 4: Get the length of a text in words\n", "\n", "We will now write a non-math oriented function. We want a function that takes as input a piece of text, and returns the number of words in it. What is the length of the article in words? For simplicity we assume that words are separated by spaces." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "article = \"\"\"One person was believed to be missing after an oil rig storage platform exploded Sunday night on Lake Pontchartrain, just north and west of New Orleans. Seven people were taken to hospitals after the explosion, and three of them remained in critical condition Monday morning, Mike Guillot, the director of emergency medical services at East Jefferson General Hospital, said at a news conference. The other four were released. Sheriff Joe Lopinto of Jefferson Parish said at the news conference, We are fairly confident there is an eighth person, adding that search efforts were continuing, and the Coast Guard had contacted the family of the person. No fatalities had been reported as of Monday morning. The blast occurred shortly after seven pm near St Charles Parish and the city of Kenner. The platform is in unincorporated Jefferson Parish. Officials are still investigating the cause of the explosion, but the City of Kenner said on its Facebook page that authorities on the scene report that cleaning chemicals ignited on the surface of the oil rig platform.\"\"\"\n", "print(article)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "words = article.split(\" \")\n", "print(words)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "len_words = len(words)\n", "print(len_words)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So, in this case, we have the input being the string variable that contains the text, and the output is a number." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def article_length(text):\n", " words = text.split(\" \")\n", " length = len(words)\n", " return length" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "len_words = article_length(article)\n", "print(f\"The article length is {len_words} words\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Advanced: Multiple outputs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# TODO: Return also the length in characters, and the length in sentences\n", "# Introduce the notion of multiple values in the output" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Returning multiple values: Example with quadratic function" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example 5: Solve the quadratic equation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here is another example of a function, again math oriented, so that you remember your high school years. \n", "\n", "We want to solve the quadratic equation $ a*x^2 + b*x + c = 0$.\n", "\n", "Recall that the solutions of a quadratic equation $a \\cdot x^2+ b \\cdot x+c$ are:\n", "\n", "* $x_1 = \\frac{−b + \\sqrt{b^2 − 4 \\cdot a \\cdot c}}{ 2 \\cdot a}$ and $ x_2 = \\frac{−b - \\sqrt{b^2 − 4 \\cdot a \\cdot c}}{ 2 \\cdot a}$ when $b^2 − 4 \\cdot a \\cdot c > 0$.\n", "* $x = \\frac{−b}{ 2 \\cdot a}$ when $b^2 − 4 \\cdot a \\cdot c = 0$.\n", "* No solutions when $b^2 − 4 \\cdot a \\cdot c < 0$\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import math\n", "a = 1\n", "b = -5.86\n", "c = 8.5408\n", "\n", "# Start solving\n", "D = b**2 - 4*a*c\n", "if D>0:\n", " x1 = (-b + math.sqrt(D) ) /(2*a)\n", " print(f\"Solution 1: {x1:.3f}\")\n", " x2 = (-b - math.sqrt(D) )/(2*a)\n", " print(f\"Solution 2: {x2:.3f}\")\n", "elif D==0:\n", " x = -b/(2*a)\n", " print(f\"Solution: {x:.3f}\")\n", "else:\n", " print(f\"No Solution\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So, let's convert the code above into a function. Let's start by taking the code above and putting it in a function." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# NOTE: This is an INCORRECT APPROACH: \n", "# Using PRINT instead of RETURN\n", "def solve_quadratic(a, b, c):\n", " \n", " D = b**2 - 4 * a * c\n", " if D > 0:\n", " x1 = (-b + math.sqrt(D) ) / (2 * a)\n", " print(f\"Solution 1: {x1:.3f}\")\n", " x2 = (-b - math.sqrt(D) ) / (2 * a)\n", " print(f\"Solution 2: {x2:.3f}\")\n", " elif D == 0:\n", " x = -b / (2 * a)\n", " print(f\"Solution: {x:.3f}\")\n", " else:\n", " print(f\"No Solution\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Attention: Common mistake 1: `print` instead of `return` " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The code above is a very common mistake for beginners. It is a tricky mistake because the program superficially seems to work fine." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = 1\n", "b = -5.86\n", "c = 8.5408\n", "solve_quadratic(a, b, c)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = 1\n", "b = 2\n", "c = 1\n", "solve_quadratic(a, b, c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice though one issue: There is no output." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = 1\n", "b = 2\n", "c = 1\n", "result = solve_quadratic(a, b, c)\n", "print(\"The result is:\", result)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So, what is the input and output in this case?\n", "\n", "For input, things are clear: We need the values for $a$, $b$, and $c$.\n", "\n", "For output? We may need to get back two, one, or no values. This is an example where we need to think before writing the code, and make a design decision. \n", "\n", "A common solution when we have situations with multiple possible outputs is to return a tuple, as we did above. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## COMMON MISTAKE 1: PRINT instead of RETURN" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Example of returning \"multivalued\" results using tuples/lists\n", "def solve_quadratic(a,b,c):\n", " # We can even check that the value of the discriminant\n", " # is positive before returning a result\n", " discr = b**2 - 4*a*c\n", " if discr < 0: # We will not compute \n", " return None # \"None\" is a special value, meaning \"nothing\"\n", " if discr == 0:\n", " solution = -b / (2 * a)\n", " return solution\n", " if discr > 0:\n", " solution1 = (-b + math.sqrt(D) ) / (2 * a)\n", " solution2 = (-b - math.sqrt(D) ) / (2 * a)\n", " # A function can return a list, tuple, dictionary, etc.\n", " # The \"return\" value does not have to be a single value\n", " return solution1, solution2\n", "\n", "solutions = solve_quadratic(a,b,c)\n", "print(\"Solutions:\", solutions )\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## COMMON MISTAKE 2\n", "# Using multiple return statements\n", "# Why? After we execute the first return, \n", "# we do not execute anything below that\n", "def s1(a, b, c):\n", " d = math.sqrt(b**2 - 4*a*c)\n", " return (-b + d)/(2*a) # solution 1 \n", " return (-b - d)/(2*a) # solution 2, BUT this will never be executed" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Functions and Loops: Cleaning up a string" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# this function takes as input a phone (string variable)\n", "# and prints only its digits\n", "def clean(phone):\n", " result = \"\"\n", " digits = {\"0\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\"}\n", " for c in phone:\n", " if c in digits:\n", " result = result + c\n", " return result \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "p = \"(800) 555-1214 Panos Phone number\"\n", "print(clean(p))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# this function takes as input a phone (string variable)\n", "# and prints only its digits\n", "def clean(phone):\n", " # We initialize the result variable to be empty. \n", " # We will append to this variable the digit characters \n", " result = \"\"\n", " # This is a set of digits (as **strings**) that will\n", " # allow us to filter the characters\n", " digits = {\"0\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\"}\n", " # We iterate over all the characters in the string \"phone\"\n", " # which is a parameter of the function clean\n", " for c in phone:\n", " # We check if the character c is a digit\n", " if c in digits:\n", " # if it is, we append it to the result\n", " result = result + c\n", " # once we are done we return a string variable with the result\n", " return result \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# This is an alternative, one-line solution that uses a list \n", "# comprehension to create the list of acceptable characters, \n", "# and then uses the join command to concatenate all the \n", "# characters in the list into a string. Notice that we use \n", "# the empty string \"\" as the connector\n", "def clean_oneline(phone):\n", " digits = {\"0\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\"}\n", " return \"\".join([c for c in phone if c in digits])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Example: Random password" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Functions and Loops: Generate a random password with `n` letters. The value `n` should be a parameter." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# This code generates one random letter\n", "import random\n", "import string\n", "random.choice(string.ascii_letters)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Variable Scopes" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "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.6" } }, "nbformat": 4, "nbformat_minor": 1 }