{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Created by [Nathan Kelber](http://nkelber.com) for [JSTOR Labs](https://labs.jstor.org/) under [Creative Commons CC BY License](https://creativecommons.org/licenses/by/4.0/)
\n", "**For questions/comments/improvements, email nathan.kelber@ithaka.org.**
\n", "![CC BY License Logo](https://ithaka-labs.s3.amazonaws.com/static-files/images/tdm/tdmdocs/CC_BY.png)\n", "____\n", "# Python Basics II\n", "\n", "**Description:** This notebook describes the basics of flow control including:\n", "* Boolean values and operators\n", "* Comparison operators\n", "* `if` statements\n", "* `else` statements\n", "* `elif` statements\n", "* `while` and `for` loop statements\n", "\n", "and the basics of writing functions:\n", "\n", "* `def` statements\n", "* Local and global scope\n", "\n", "This is part 2 of 3 in the series Python Basics that will prepare you to do text analysis using the Python programming language.\n", "\n", "**Difficulty:** Beginner\n", "\n", "**Purpose:** Learning (Optimized for explanation over code)\n", "\n", "**Knowledge Required:** \n", "* [Getting Started with Jupyter Notebooks](./0-introduction-to-jupyter-notebooks.ipynb)\n", "* [Python Basics I](./0-python-basics-1.ipynb)\n", "\n", "**Knowledge Recommended:** None\n", "\n", "**Completion Time:** 90 minutes\n", "\n", "**Data Format:** None\n", "\n", "**Libraries Used:** `random` to generate random numbers\n", "___" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## What is a **flow control statement**?\n", "\n", "In Python Basics I, you learned about expressions, operators, variables, and a few native Python functions. We wrote programs that executed line-by-line, starting at the top and running to the bottom. This approach works great for simple programs that may execute a few tasks, but as you begin writing programs that can do multiple tasks you'll need a way for your programs to decide which action comes next. We can control when code gets executed with **flow control statements**. If a program is a set of steps for accomplishing a task, then **flow control statements** help the program decide the next action. \n", "\n", "**Flow control statements** work like a flowchart. For example, let's say your goal is to hang out and relax with friends. There are a number of steps you might take, depending on whether your friends are available or you feel like making some new friends.\n", "\n", "![Flowchart to hangout with friends](https://ithaka-labs.s3.amazonaws.com/static-files/images/tdm/tdmdocs/friends_flowchart.png)\n", "\n", "Each diamond in our flowchart represents a decision that has to be made about the best step to take next. This is the essence of **flow control statements**. They help a program decide what the next step should be given the current circumstances. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Boolean Values\n", "\n", "One way we to create flow control statements is with boolean values that have two possible values: **True** or **False**. In our example above, we could consider a \"Yes\" to be \"True\" and a \"No\" to be \"False.\" When we have the data we need to answer each question, we could store that answer in a variable, like:\n", "\n", "* ```are_friends_available = False```\n", "* ```make_new_friends = True```\n", "* ```new_friend_available = True```\n", "\n", "This would allow us to determine which action to take next. When we assign boolean values to a variable, the first letter must be capitalized: " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Note, the first letter of a boolean value must always be capitalized in Python\n", "are_friends_available = false\n", "print(are_friends_available)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# The boolean values **True** and **False** cannot be used for variable names. \n", "# Treating the boolean value True as a variable will create an error\n", "True = 7" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Comparison Operators\n", "Now that we have a way to store integers, floats, strings, and boolean values in variables, we can use a **comparison operator** to help make decisions based on those values. We used the comparison operator ```==``` in Python Basics I. This operator asks whether two expressions are equal to each other. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Comparing two values with the comparison operator ==\n", "67 == 67" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Note, a comparison operator uses ==\n", "# Do not confuse with variable assignment statement which uses =\n", "67 = 67" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are additional **comparison operators** that can help us with flow control.\n", "\n", "|Operator|Meaning|\n", "|---|---|\n", "|==|Equal to|\n", "|!=|Not equal to|\n", "|<|Less than|\n", "|>|Greater than|\n", "|<=|Less than or equal to|\n", "|>=|Greater than or equal to|" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Using the \"Not equal to\" operator\n", "67 != 32" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Using the \"Not equal to\" operator\n", "67 != 67" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Using the \"equal to\" operator with strings\n", "'hello world' == 'hello world'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Using the \"equal to\" operator to compare a string with an integer\n", "'55' == 55 # A string cannot be equal to a float or an integer" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Using the \"equal to\" operator to compare an integer with a float\n", "55 == 55.0 # An integer can be equal to a float" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Using a comparison operator on a variable\n", "number_of_dogs = 1 # Creating a variable number_of_dogs\n", "number_of_dogs >= 1 # Checking whether number_of_dogs is greater than or equal to 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Boolean Operators (and/or/not)\n", "We can also use Boolean operators (and/or/not) to create expressions that evaluate to a single Boolean value (True/False). \n", "\n", "### Using the Boolean Operator ```and```\n", "The ```and``` operator determines whether *both* conditions are True." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# If condition one is True AND condition two is True\n", "# What will the evaluation be?\n", "True and True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# If condition one is True AND condition two is False\n", "# What will the evaluation be?\n", "True and False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In order for an ```and``` expression to evaluate to True, every condition must be True. Here is the \"Truth Table\" for every pair:\n", "\n", "|Expression|Evaluation|\n", "|---|---|\n", "|True and True|True|\n", "|True and False|False|\n", "|False and True|False|\n", "|False and False|False|\n", "\n", "Since ```and``` expressions require all conditions to be True, they can easily result in False evaluations.\n", "\n", "### Using the Boolean Operator ```or```\n", "The ```or``` operator determines whether *any* condition is True." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Is expression one True OR is expression two True?\n", "True or False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Is condition one True OR is condition two True?\n", "False or False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An ```or``` expression evaluates to True if *any* condition is True. Here is the \"Truth Table\" for every pair:\n", "\n", "|Expression|Evaluation|\n", "|---|---|\n", "|True or True|True|\n", "|True or False|True|\n", "|False or True|True|\n", "|False or False|False|\n", "\n", "Since ```or``` expressions only require a single element to be True, they often result in True evaluations.\n", "\n", "### Using the Boolean Operator ```not```\n", "The```not``` operator only operates on a single condition, essentially flipping True to False or False to True. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# The not operator flips a True to False\n", "not True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Combining Boolean and Comparison Operators\n", "\n", "We can combine Boolean and comparison operators to create even more nuanced condition tests." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Evaluating two conditions with integers at once\n", "(3 < 22) and (60 == 34) # What does each condition evaluate to?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Evaluating two conditions with integers at once\n", "(3 == 45) or (3 != 7) # What does each condition evaluate to?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So far, we have evaluated one or two conditions at once, but we could compare even more at once." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Evaluating four conditions at once\n", "(3 < 7) and ('Hello' != 'Goodbye') and (17 == 17.000) and (2 + 2 != 4) # What does each condition evaluate to?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Boolean operators also have an order of operations like mathematical operators. They resolve in the order of `not`, `and`, then `or`. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The General Format of Flow Control Statements\n", "\n", "The general form of a flow control statement in Python is a condition followed by an action clause:\n", "\n", "`In this condition:`
\n", "       `perform this action`\n", "\n", "Let's return to part of our flowchart for hanging out with friends.\n", "\n", "![Flowchart showing if homework is yes then do assignment](https://ithaka-labs.s3.amazonaws.com/static-files/images/tdm/tdmdocs/do_homework_chart.png)\n", "\n", "We can imagine a flow control statement that would look something like:\n", "\n", "`if have_homework == True:`
\n", "        `complete assignment`\n", " \n", "The condition is given followed by a colon (:). The action clause then follows on the next line, indented into a **block**. \n", "\n", "* If the condition is fulfilled, the action clause in the block of code is executed. \n", "* If the condition is not fulfilled, the action clause in the block of code is skipped over." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Blocks of Code\n", "A block is a snippet of code that begins with an indentation. A block can be a single line or many lines long. Blocks can contain other blocks forming a hierarchal structure. In such a case, the second block is indented an additional degree. Any given block ends when the number of indentations in the current line is less than the number that started the block. \n", "\n", "![Visualization of code block indentations](https://ithaka-labs.s3.amazonaws.com/static-files/images/tdm/tdmdocs/code_block_indentation.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Kinds of Flow Control Statements\n", "\n", "The code example above uses an `if` statement, but there are other kinds of flow control statements available in Python. \n", "\n", "|Statement|Means|Condition for execution|\n", "|---|---|---|\n", "|`if`|if|if the condition is fulfilled|\n", "|`elif`|else if|if no previous conditions were met *and* this condition is met|\n", "|`else`|else|if no condition is met (no condition is supplied for an `else` statement)|\n", "|`while`|while|while condition is true|\n", "|`for`|for|execute in a loop for this many times|\n", "\n", "Let's take a look at each of these flow control statement types." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## `if` Statements\n", "\n", "An `if` statement begins with an expression that evaluates to True or False.\n", "\n", "* if True, then perform this action\n", "* if False, skip over this action\n", "\n", "In practice, the form looks like this:\n", "\n", "`if this is True:`
\n", "        `perform this action`\n", "\n", "Let's put an `if` statement into practice with a very simple program that asks the user how their day is going and then responds. We can visualize the flow of the program in a flowchart.\n", "\n", "![Flowchart of a good day program](https://ithaka-labs.s3.amazonaws.com/static-files/images/tdm/tdmdocs/good_day_flowchart.png)\n", "\n", "Our program will use two `if` statements, one response if the user types \"Yes\" and a second response for \"No\"." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# A program that responds to whether the user is having a good or bad day\n", "print('Are you having a good day? (Yes or No)') # Ask user if they are having a good day\n", "having_good_day = input() # Define a variable having_good_day to hold the user's input\n", "\n", "if having_good_day == 'Yes' or having_good_day == 'yes': # If the user has input the string 'Yes' or 'yes'\n", " print('Glad to hear your day is going well!') # Print: Glad to hear your day is going well!\n", "\n", "if having_good_day == 'No' or having_good_day == 'no': # If the user has input the string 'No' or 'no'\n", " print('Sorry to hear that. I hope it gets better.') # Print: Sorry to hear that. I hope it gets better." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Our program works fairly well so long as the user inputs 'Yes' or 'No'. If they type something else, it simply ends. We may want to insert a final condition that notifies the user in this case. We can do this with an `else` flow control statement." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## `else` Statements\n", "\n", "An `else` statement does not require a condition, it simply executes if none of the previous conditions are met. The form looks like this:\n", "\n", "`else:`
\n", "        `perform this action`\n", "\n", "Our updated flowchart now contains a third branch for our program.\n", "\n", "![The program flowchart with three branches](https://ithaka-labs.s3.amazonaws.com/static-files/images/tdm/tdmdocs/friends_flowchart_with_else.png)\n", " \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# A program that responds to whether the user is having a good or bad day\n", "print('Are you having a good day? (Yes or No)') # Ask user if they are having a good day\n", "having_good_day = input() # Define a variable having_good_day to hold the user's input\n", "\n", "if having_good_day == 'Yes' or having_good_day == 'yes': # If the user has input the string 'Yes' or 'yes'\n", " print('Glad to hear your day is going well!') # Print: Glad to hear your day is going well!\n", " \n", "elif having_good_day == 'No' or having_good_day == 'no': # else if the user has input the string 'No'\n", " print('Sorry to hear that. I hope it gets better.') # Print: Sorry to hear that. I hope it gets better.\n", " \n", "else: # Execute this if none of the other branches executes\n", " print('Sorry, I only understand \"Yes\" or \"No\"') # Note that we can use double quotations in our string because it begins and ends with single quotes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Our new program is more robust, giving users feedback for three different kinds of input. The new `else` statement helps users know when their input is not understood. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## `elif` Statements\n", "\n", "An `elif` statement, short for \"else if,\" allows us to create a list of possible conditions where one (and only one) action will be executed. `elif` statements come after an initial `if` statement and before an `else` statement:\n", "\n", "`if condition A is True:`
\n", "        `perform action A`
\n", "`elif condition B is True:`
\n", "        `perform action B`
\n", "`elif condition C is True:`
\n", "        `perform action C`
\n", "`elif condition D is True:`
\n", "        `perform action D`
\n", "`else:`
\n", "       `perform action E`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Why use `elif` instead of `if`?\n", "\n", "When an `elif` condition is met, all other `elif` statements are skipped over. This means that one (and only one) flow control statement is executed when using `elif` statements. The fact that only one `elif` statement is executed is important because it may be possible for multiple conditions to be True. A series of `elif` statements evaluates from top-to-bottom, only executing the first `elif` statement whose condition evaluates to True. The rest of the `elif` statements are skipped over (whether they are True or not). \n", "\n", "In practice, a set of mutually exclusive `if` statements will result in the same actions as an `if` statement followed by `elif` statements. There are a few good reasons, however, to use `elif` statements:\n", "\n", "1. A series of `elif` statements helps someone reading your code understand that a single flow control choice is being made.\n", "2. Using `elif` statements will make your program run faster since other conditional statements are skipped after the first evaluates to True. Otherwise, every `if` statement will be evaluated.\n", "3. Writing a mutually exclusive set of `if` statements can be very complex.\n", "\n", "Expanding on the concept of our \"How is your day going?\" program, let's take a look at an example that asks the user \"How is your week going?\" It will take two inputs: the day of the week and how the user feels the week is going.\n", "\n", "![How is your week going flowchart](https://ithaka-labs.s3.amazonaws.com/static-files/images/tdm/tdmdocs/good_week_elif.png)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# A program that responds to the user's input for the day of the week and how their week is going.\n", "print('What day of the week is it?')\n", "day_of_week = input() \n", "print('Are you having a good week?')\n", "having_good_week = input()\n", "\n", "if day_of_week == 'Friday' or day_of_week == 'friday':\n", " print('Enjoy the weekend!')\n", " \n", "elif having_good_week == 'Yes' or having_good_week == 'yes':\n", " print('I hope the rest of the week is good too!')\n", " \n", "elif having_good_week == 'No' or having_good_week == 'no':\n", " print('Sorry to hear that. I hope the rest of the week is better.')\n", " \n", "else:\n", " print('Sorry, I only understand \"Yes\" or \"No\"')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the program above, try changing the `elif` statements to `if` statements. What happens if the user inputs 'Friday' and 'Yes'?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## `while` Loop Statements\n", "\n", "So far, we have used flow control statements like decision-making branches to decide what action should be taken next. Sometimes, however, we want a particular action to loop (or repeat) until some condition is met. We can accomplish this with a `while` loop statement that takes the form:\n", "\n", "`while condition:`
\n", "       `take this action`\n", "\n", "After the code block is executed, the program loops back to check and see if the `while` loop condition has changed from True to False.\n", "\n", "In the following program, the user will guess a number until they get it correct. \n", "\n", "![flowchart for number-guessing program](https://ithaka-labs.s3.amazonaws.com/static-files/images/tdm/tdmdocs/guess_number_flowchart.png)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# A program that asks the user to guess a number\n", "secret_number = str(4) # The secret number is set here by the programmer. Notice it is turned into a string so it can be easily compared with user inputs.\n", "print('I am thinking of a number between 1-10. Can you guess it?') # Ask the user to make a guess\n", "guess = 0 # Set the guess to 0 to start\n", "guess = input() # Take the user's first guess\n", "while guess != secret_number: # While the users guess does not equal secret_number\n", " print('Nope. Guess again!') # Print \"Nope. Guess Again!\"\n", " guess = input() # Allow the user to change the value of guess\n", "print('You guessed the secret number, ' + str(secret_number)) # Print a congratulations message with the secret number" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Stopping Accidental Infinite Loops\n", "When using a `while` loop, it is possible to accidentally create an infinite loop that never ends. If you accidentally write code that repeats infinitely, you can stop the execution by selecting **interrupt kernel** in the **Kernel** menu. (Alternatively, you can press the letter **i** twice on your keyboard.) You may also want to remove the output of the rogue cell. You can do this by selecting the problematic cell and then **clear output** in the **Edit** menu. (Alternatively, you can click the cell and choose **clear output**. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# An infinite loop\n", "while True:\n", " print('Oh noes!')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A `while` loop that repeats a specified number of times\n", "\n", "In the program above, the `while` loop checked to see if the user guessed a particular number. We could also use a `while` loop to repeat a code block a particular number of times. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# A simple program that prints out 1, 2, 3\n", "number = 0\n", "while number < 3:\n", " number = number + 1 # We can also write an equivalent shortcut: number += 1\n", " print(number)\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## `for` Loop Statements with a `range()` Function\n", "\n", "An abbreviated way to write a `while` loop that repeats a specified number of times is using a `for` loop with a `range()` function. This loop takes the form:\n", "\n", "`for i in range(j):`
\n", "       `take this action`\n", " \n", "where `i` is a generic variable for counting the number of iterations and `j` is the number of times you want the block to repeat." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# A `for` loop that repeats 'What?' five times. Changing the `range()` number will change the number of repetitions.\n", "for i in range(5):\n", " print('What?')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# A `for` loop that prints the value of the current iteration, here called `i`. \n", "for i in range(5):\n", " print(i)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the examples above, the `range()` function takes a single argument that specifies the number of loops. The assumption is our `range()` function will start at 0, but we can specify any starting integer by adding an additional argument." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# A `for` loop that starts looping at 27 and stops looping at 32\n", "for i in range(27,32):\n", " print(i)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# A `for` loop that starts looping at -13 and stops looping at 7\n", "for i in range(-3, 7):\n", " print(i)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also specify the size of each step for the `range()` function. In the above examples, the function adds one for each increment step, but we can add larger numbers or even specify negative numbers to have the `range()` function count down. The general form is:\n", "\n", "`for i in range(start, stop, increment):`
\n", "        `loop this action`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# A `for` loop that counts down from ten to one, followed by printing `Go!`\n", "for i in range(10, 0, -1):\n", " print(i)\n", "print('Go!')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## `Continue` and `Break` Statements\n", "`while` loops and `for` loops can also use `continue` and `break` statements to affect flow control. \n", "* A `continue` statement immediately restarts the loop.\n", "* A `break` statement immediately exits the loop.\n", "\n", "Let's return to our secret number guessing program. This time we'll create the same flow control but using `continue` and `break` statements.\n", "\n", "![Flowchart for secret number guessing program](https://ithaka-labs.s3.amazonaws.com/static-files/images/tdm/tdmdocs/guess_number_flowchart.png)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# A program that asks the user to guess a number\n", "guess = 0\n", "secret_number = str(4) # The secret number is set here by the programmer. Notice it is turned into a string so it can be easily compared with user inputs.\n", "print('I am thinking of a number between 1-10.') # Ask the user to make a guess\n", "while True:\n", " print('What is your guess?')\n", " guess = input()\n", " if guess == secret_number:\n", " break\n", " else:\n", " continue\n", "print('You guessed the secret number, ' + secret_number) # Print a congratulations message with the secret number" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Functions\n", "\n", "We have used several Python functions already, including `print()`, `input()`, and `range()`. You can identify a function by the fact that it ends with a set of parentheses `()` where **arguments** can be **passed** into the function. Depending on the function (and your goals for using it), a function may accept no arguments, a single argument, or many arguments. For example, when we use the `print()` function, a string (or a variable containing a string) is passed as an argument.\n", "\n", "Functions are a convenient shorthand, like a mini-program, that makes our code more **modular**. We don't need to know all the details of how the `print()` function works in order to use it. Functions are sometimes called \"black boxes,\" in that we can put an *argument* into the box and a *return value* comes out. We don't need to know the inner details of the \"black box\" to use it. (Of course, as you advance your programming skills, you may become curious about how certain functions work. And if you work with sensitive data, you may *need* to peer in the black box to ensure the security and accuracy of the output.) \n", "\n", "# Libraries and Modules\n", "\n", "While Python comes with many functions, there are thousands more that others have written. Adding them all to Python would create mass confusion, since many people could use the same name for functions that do different things. The solution then is that functions are stored in **modules** that can be **imported** for use. A module is a Python file (extension \".py\") that contains the definitions for the functions written in Python. These modules (individual Python files) can then be collected into even larger groups called **packages** and **libraries**. Depending on how many functions you need for the program you are writing, you may import a single **module**, a **package** of modules, or a whole **library**. \n", "\n", "## Import Statement for a module\n", "\n", "The general form of importing a module is:\n", "`import module_name`\n", "\n", "You may recall from the introduction to Jupyter notebooks, we imported the `time` module and used the `sleep()` function to wait 5 seconds." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print('Waiting 5 seconds...')\n", "import time # We import the `time` module\n", "time.sleep(5) # We run the sleep() function from the time module using `time.sleep()`\n", "print('Done')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also just import the `sleep()` function without importing the whole module. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print('Waiting 5 seconds...')\n", "from time import sleep # We import just the sleep() function from the time module\n", "sleep(5) # Notice that we just call the sleep() function, not time.sleep\n", "print('Done')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# How to Write a Function\n", "\n", "In the above examples, we **called** a function that was already written. To call our own functions, we need to define our function first with a **function definition statement** followed by a code block:\n", "\n", "`def my_function():`
\n", "       `do this task`\n", " \n", "\n", "After the function is defined, we can **call** on it to do us a favor whenever we need by simply executing the function like so:\n", "\n", "`my_function()`\n", "\n", "Once the function is defined, we can call it as many times as we want without having to rewrite its code. In the example below, we call `my_function` twice. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Creating a simple function to double a number\n", "print('I will double any number. Give me a number.')\n", "inputnumber = input()\n", "\n", "def my_function():\n", " outputnumber = int(inputnumber) * 2\n", " print(outputnumber)\n", "\n", "my_function()\n", "\n", "print('Give me a new number.')\n", "inputnumber = input()\n", "\n", "my_function()\n", "\n", "print('Give me one last number.')\n", "inputnumber = input()\n", "\n", "my_function()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using functions also makes it easier for us to update our code. Let's say we wanted to change our program to square our `inputnumber` instead of doubling it. We can simply change the function definition one time to make the change everywhere. See if you can make the change. (Remember to also change your program description in the first line!)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Creating a simple function to double a number\n", "print('I will double any number. Give me a number.')\n", "inputnumber = input()\n", "\n", "def my_function():\n", " outputnumber = int(inputnumber) * 2\n", " print(outputnumber)\n", "\n", "my_function()\n", "\n", "print('Give me a new number.')\n", "inputnumber = input()\n", "\n", "my_function()\n", "\n", "print('Give me one last number.')\n", "inputnumber = input()\n", "\n", "my_function()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By changing our function one time, we were able to make our program behave differently in three different places. Generally, it is good practice to avoid duplicating program code to avoid having to change it in multiple places. When programmers edit their code, they may spend time **deduplicating** to make the code easier to read and maintain." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Parameters vs. Arguments\n", "\n", "When we write a function definition, we can define a **parameter** to work with the function. We use the word **parameter** to describe the variable in parentheses within a function definition:\n", "\n", "`def my_function(input_variable):`
\n", "       `do this task`\n", "\n", "In the pseudo-code above, `input_variable` is a parameter because it is being used within the context of a function definition. When we actually call and run our function, the information we pass in is called an `argument`. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# A program to greet the user by name\n", "\n", "def greeting_function(user_name): #`user_name` here is a parameter since it is in the definition of the `greeting_function`\n", " print('Hello ' + user_name)\n", "\n", "greeting_function('Sam') # 'Sam' is an argument that is being passed into the `greeting_function`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the above example, we passed a string into our function, but we could also pass a variable." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# A program to greet the user by name\n", "\n", "def greeting_function(user_name): #`user_name` here is a parameter since it is in the definition of the `greeting_function`\n", " print('Hello ' + user_name)\n", "\n", "print('What is your name?')\n", "answer = input()\n", "greeting_function(answer) # `answer` is an argument that is being passed into the `greeting_function`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Function Return Values\n", "\n", "Whether or not a function takes an argument, it will return a value. If we do not specify that return value in our function definition, it is automatically set to `None`, special value like the Boolean `True` and `False` that simply means null or nothing. (`None` is not the same thing as, say, the integer `0`.) We can also specify return values for our function using flow control." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# A fortune-teller program that uses a random integer\n", "\n", "import random # importing a function that will give us a random number\n", "\n", "def fortune_picker(fortune_number): # A function definition statement that has a parameter `fortune_number`\n", " if fortune_number == 1:\n", " return 'You will have six children'\n", " elif fortune_number == 2:\n", " return 'You will become very wise'\n", " elif fortune_number == 3:\n", " return 'A new friend will help you find yourself'\n", " elif fortune_number == 4:\n", " return 'Do not eat the sushi'\n", " elif fortune_number == 5:\n", " return 'That promising venture... it is a trap.'\n", " elif fortune_number == 6: \n", " return 'Sort yourself out then find love.'\n", "\n", "# Asks the user if they would like a fortune and takes that input into `get_a_fortune`\n", "print('Would you like your fortune?') \n", "get_a_fortune = input()\n", "\n", "# If get_a_fortune is yes, give them a fortune. Otherwise print 'Maybe next time'.\n", "if get_a_fortune == 'yes':\n", " random_number = random.randint(1,6) # Choose a random number between 1 and 6 and assign it to a new variable `random_number`\n", " fortune_string = fortune_picker(random_number)\n", " print(fortune_string)\n", "else: print('Maybe next time')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Local and Global Scope\n", "\n", "We have seen that functions make maintaining code easier by avoiding duplication. One of the most dangerous areas for duplication is variable names. As programming projects become larger, the possibility that a variable name will be re-used goes up. This can cause weird errors in our programs that are hard to track down. We can alleviate the problem of duplicate variable names through the concepts of **local scope** and **global scope**.\n", "\n", "We use the phrase **local scope** to describe what happens within a function. The **local scope** of a function may contain **local variables**, but once that function has completed the **local variables** and their contents are erased. \n", "\n", "On the other hand, we can also create **global variables** that persist at the top-level of the program *and* within the **local scope** of a function.\n", "\n", "* In the **global scope**, Python does not recognize any **local variables** from within functions\n", "* In the **local scope** of a function, Python can recognize and modify any global variables\n", "* It is possible for there to be a **global variable** and a **local variable** with the same name\n", "\n", "Ideally, Python programs should limit the number of global variables and create most variables in a local scope." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Demonstration of global variable being use in a local scope\n", "# The program crashes when a local variable is used in a global scope\n", "global_secret_number = 7\n", "\n", "def share_number():\n", " local_secret_number = 13\n", " print('The global secret number is ' + str(global_secret_number))\n", " print('The local secret number is ' + str(local_secret_number))\n", " \n", "\n", "share_number()\n", "print('The global secret number is ' + str(global_secret_number))\n", "print('The local secret number is ' + str(local_secret_number))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The code above defines a **global variable** `global_secret_number` with the value of 7. A function, called `share_number`, then defines a **local variable** `local_secret_number` with a value of 13. When we call the `share_number` function, it prints the local and the global variables. After the `share_number()` function completes we try to print both variables in a **global scope**. The program prints `global_secret_number` but crashes when trying to print `local_secret_number` in a **global scope**. \n", "\n", "It's a good practice not to name a **local variable** the same thing as a **global variable**. If we define a variable with the same name in a **local scope**, it becomes a **local variable** within that scope. Once the function is closed, the **global variable** retains its original value." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# A demonstration of global and local scope using the same variable name\n", "secret_number = 7\n", "\n", "def share_number():\n", " secret_number = 10\n", " print(secret_number)\n", "\n", "share_number()\n", "print(secret_number)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The Global Statement\n", "\n", "A **global statement** allows us to modify a **global variable** in a **local scope**. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Using a global statement in a local scope to change a global variable locally\n", "\n", "secret_number = 7\n", "\n", "def share_number():\n", " global secret_number # The global statement indicates this the global variable, not a local variable\n", " secret_number = 10\n", " print(secret_number)\n", "\n", "share_number()\n", "print(secret_number)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "___\n", "# Start Next Lesson: [Python Basics III](./0-python-basics-3.ipynb)" ] } ], "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.7.6" } }, "nbformat": 4, "nbformat_minor": 4 }