## Module #3

In this module you will learn how we can design programs that let Python ask 'questions' - in essence, this lets us write programs that have the ability to make decisions based on certain conditions. To do that we'll need to understand the concepts of boolean logic and a decision structure known as an `if` statement and its related statements. In addition we'll introduce you to some basic Python Modules that add additional functionality to make our programs more interesting.

### Boolean Data

So far we have discussed three different "data types" in Python - 'strings' for sequences of characters, 'integers' for whole numbers and 'floats' for numbers that contain a decimal point. The video below will introduce you to a fourth data type called the 'Boolean' data type. This data type is used to store 'logical' values - that is, values that can be one either `True` or `False`. We use logical values all the time in our program to determine if a particular condition exists (i.e. did the user type their username into a form correctly? The answer to that question is either `True` or `False`).

In addition to the 'string', 'int', and 'float' data types you've already learned about, there is another data type called the Booleans data type (bool for short). A Boolean is a value of either `True` or `False`.

Note: capitalization is important - `True` is not the same as `true`.

Recall that all expressions in Python evaluate to a value that has a data type. For example, the addition problem in the following expression evaluates to an 'integer' because both of the operands are 'integers':

`print (5 + 7)`

A Boolean expression is an expression that evaluates to a value that has a data type of Boolean (i.e. `True` or `False`). We can write Boolean expressions using comparision operators which allow us to compare two values.

There are six comparision operators that we use in Python - the table below gives examples of how each of the comparision operators can be used:

```x == y     # EQUALITY:                 is x equal to y?
x != y     # INEQUALITY:               is x not equal to y?
x > y      # GREATER THAN:             is x greater than y?
x >= y     # GREATER THAN OR EQUAL TO: is x greater than or equal to y?
x < y      # LESS THAN:                is x less than y?
x <= y     # LESS THAN OR EQUAL TO:    is x less than or equal to y?```

Any expression that uses a comparision operator evaluates to a Boolean value. For example, `5 > 3` asks a question - "is 5 greater than 3?" - the answer here is "Yes", so the expression evaluates to the Boolean value of `True`

Note: the `=` symbol is the assignment operator used to assign values to variables, while `==` is a comparison operator used to check for equality. The two are not interchangeable.. Also note that there is no `=<`, `=>`, or `=!` operators, the non-equals symbols (`!`, `<`, and `>`) always come first when writing a comparision operator.

#### Logical Operators

A logical operator is an operator that lets you combine multiple boolean expressions. There are three logical operators: `and`, `or`, and `not`.

For example, assume you have a variable called 'x' that is holding the value 5:

`x = 5`

If we wanted to test to see if the value being held in the variable 'x' is between 3 and 7 we would need to test two different conditions:

```is x >= 3?
is x <= 7?
```

However, each one of these expressions only tests one condition - the first one determines if x is greater than 3, and the second one determines if x is less than 7. We actually need the answer to both of these questions to be `True` to determine if a number is between 3 and 7. We can do this using the `and` logical operator, like this:

`x > 3 and x < 7`

Python first evaluates each of the Boolean expressions independently. Next, it sees the "and" logical operator between them - this "connects" the two expressions and says "if the first expression evaluates to `True` AND the second expression evaluates to `True` then the whole expression evaluates to `True`"

The semantics (the meaning of) the logical operators in Python are the same as they are in a natural language (a spoken language). Here are a few tables that show how these operators work:

"and" operator
```# the "and" operator is the most restrictive logical operator
# it will evaluate to True only if all of its operands also evaluate to True

Operand 1			Operand 2	Result
True		and		True		True
True		and		False		False
False		and		True		False
False		and		False		False```
"or" operator
```# the "or" operator is less restrictive than the "and" operator
# it will evaluate to True if any one of its operands evaluete to True

Operand 1			Operand 2	Result
True		or		True		True
True		or		False		True
False		or		True		True
False		or		False		False```
"not" operator
```# the "not" operator negates a Boolean expression
# it "flips" True's to False's and False's to True's

Operand 1	Result
not True	False
not False	True```

Here are some examples:

```x < 0 or x > 10     # True if x is less than 0 *or* x is greater than 10;
# otherwise False
x > 0 and x < 100   # True if x is greater than 0 *and* x is less than 10;
# otherwise False
not x < 0           # True if x is *not* less than 0; otherwise False```

#### Order of operations

When we see an expression that has multiple operators (any combination of mathematical, comparison, or logical operators) we need to know what order to perform those operations. The order is determined by predefined precedence given by the following table which is ordered from the highest precedence (done first) to the lowest precedence (done last):

Order of OperationsOperator(s)Operator Type
Done 1st( )specify order of operations
2nd**exponentiation
3rd*, /, //, %multiplicative
5th==, !=, <=, >=, <, >comparison
6thnotlogical
7thandlogical
Done lastorlogical

Given this order of operations notice the equivalence relationship between the following statements:

```# Following two lines are equivalent:
x-1 >= 2 and y*3 <= 4
((x-1) >= 2) and ((y*3) <= 4)

# Following three lines are equivalent:
x == 1 and not y == 2
(x == 1) and not (y == 2)
(x == 1) and (not (y == 2))
```
Sample Program: This program contains a number of 'print' statements - using what you learned in this mobule about Boolean expressions, comparision operators, logical operators and order of operations, try "tracing the output" of the program before you run it. Click the "Run" button to check your answers!

### Conditional Statements

Conditional statements (also known as "selection statements" or "if statements") are statements that execute different lines of code based on a Boolean condition. These kinds of statements allow us to have our programs "ask questions" and make their own decisions while the program is running.

#### One-way "if" Statements

Conditional statements are written in Python using the `if` keyword followed by a Boolean expression and a colon. An `if` statement will execute the statements inside of its body given a certain condition is `True`. Let's begin with a simple "one-way 'if' statement" example:

Sample Program: This program showcases a "one way 'if' statement' - the code indented below the `if` statement below will only execute if the Boolean condition attached to the `if` statement evaluates to `True`. Click the "Run" button to see the program in action or download a copy.

In this example we are evaluating a condition using an `if` statement. This tells Python to compute the result of a Boolean expression - if the result is `True` then the code that is indented under the `if` statment will be executed. Note the 'colon' character at the end of the line that contains the `if` statement - this is required by Python and will generate a syntax error if it is omitted. Note that the print statement that is not indented under the `if` statement will always execute since it is not part of the "block" of code indented under the `if` statement.

There can be multiple statements inside a code block and these statements are executed in sequential order (one after another).

Note: Indention is critical! Python needs you to consistently indent your code so that it can determine which statements are associated with which `if` statements.

#### Two-way "if" statements

If the condition attached to an `if` statements evalutes to `True` then the code block indented under that `if` statement is executed. However, there are times when we want to run a different block of code if the result of the Boolean expression is `False` We can do this by using the optional `else` statement.

The `else` statement is positioned after the `if` statement at the same level of indentation. If the Boolean condition associated with the `if` statement evaluates to `True` then Python will execute the code indented under the `if` statement and skip the `else` statement. However, if the condition evalutes to `False` then Python will skip the `if` statement and execute the `else` statement instead. Here's an example:

Sample Program: This program showcases a "two way 'if' statement' - the code indented below the `if` statement below will only execute if the Boolean condition attached to the `if` statement evaluates to `True`. If the Boolean condition evalutes to `False`, however, then Python will skip that block and instead execute the block associated with the `else` statement. Click the "Run" button to see the program in action or download a copy.

#### Multi-Way "if" Statements

There are times when a two-way `if` statement won't work because the quesiton you are asking has more than two possible answers. We can do this in Python by using a "multi-way 'if' statement" which is implemented using the optional `elif` keyword. In essence, this keyword lets us ask "follow-up" questions after we ask the intial question using an `if` statement. Here's an example:

Sample Program: This program showcases a "multi way 'if' statement' - the code indented below the `if` statement below will only execute if the Boolean condition attached to the `if` statement evaluates to `True`. If the Boolean condition evalutes to `False` Python will ask a "follow-up" question using the `elif` statmement. An conditional statement can have any number of `elif` statements in it. If any of the `elif` statements evaluate to `True` then Python will execute the statements associated with that item and skip the rest. If Python finds that no Boolean expressions evaluate to `True` within a "multi-way 'if' statement" then it will execute the code associated with the `else` block. Note that `elif` and `else` are optional statements and are not required (but they are incredibly helpful when used appropriately!). Click the "Run" button to see the program in action or download a copy.

#### Nested "if" Statements

Sometimes you will want to ask additional questions inside of the body of another `if` statement. We can do this by "nesting" an `if` statement inside of another `if` statement. Here's are a few examples of this process:

Sample Program: This program contains two `if` statements. The "outer" statement determines if the number is postive or not. If it's positive then we ask a "follow-up" question by writing a new `if` statement inside of the outer statement. Click the "Run" button to see the program in action or download a copy.

Sample Program: This program uses a number of "nested" `if` statements to convert a numeric grade into a letter grade. Click the "Run" button to see the program in action or download a copy.

Note: with each layer of nesting, the indention amount increases by a constant amount. You can tell which else blocks match up with which `if` blocks by seeing which `if` statements line up vertically with which `else` statements.

#### Programming Challenges

As mentioned in the video above, `if` statements are fundamental to computer programming - you will most likely need to use them in every program you write for the rest of the semester. Take a moment to test your understanding of `if` statements by attempting to solve the following challenges.

Programming Challenge: Write a program that asks the user for the value of a coin. Then determine what kind of coin they entered using this information. Here's a sample running of the program:
```Enter a coin value: 1
That's a penny!```
... and here's another running:
```Enter a coin value: 25
That's a quarter!```
... and a third running:
```Enter a coin value: 99
That's not a valid coin!```

Programming Challenge: Write a program that asks the user for a number between 1 and 5 (inclusive). Then report to the user the following:

• If the number is even
• If the nubmer is odd
• If the number is prime
• If the number is not prime

Ensure that the user enters a number betwen 1 and 5 (you can print an error message if they supply an invalid number). Click the "Run" button to check your work, and click here to download the solution.

Programming Challenge: Write a program that asks the user for the price of an item they are purchasing. Items are eligible for a discount based on their price as follows:

• \$10 or less: no discount
• Between \$10 and \$50: 10% discount
• Over \$50: 20% discount

Ensure that you don't allow the user to enter negative values or zero as a price value. Click the "Run" button to check your work, and click here to download the solution.

### Short-Circuit Evaluation

When we have a Boolean expression that uses `and` or `or`, most programmming languages iwill use what is called short-circuit evaluation to evaluate the expression in the most efficient way possible.

In programming, certain Boolean expressions can be fully evaluated without having to execute every single part of the statement. For example, consider the following example:

`A > B or C > D`

If Python executes this statement it will begin by computing `A > B`, which can be either `True` or `False`. Remember that the `or` operator will yield a `True` result if either statement it connects evaluates to `True`. So if `A > B` evaluates to `True` then there is really no need to move on and evaluate `C > D` - so Python skips it and moves on!

Likewise, consider the following statement:

`A > B and C > D`

Python will begin to evaluate this expression just in the previous example, but in this case we are connecting the two sub-expressions with the `and` operator. If the first expression evaluates to `False` then there is really no need to continue - there's no way the expression can evaluate to `True` since the `and` operator will only yield a `True` result if both Boolean expressions evaluate to `True`.

### Basic Python Modules

The Python programming language contains a core set of functions that you can freely use in your programs, such as `print` `format` and `input`. However, there are times when you will want to access more "specialized" functions that are not part of the core Python package. For example, let's say you are writing a video game that needs to compute the angle between two characters on the screen. To do this you would probably need access to some basic trigonometry functions such as `sin`, `cos` and `tan` - but these functions are not built into Python. Thankfully Python supports the ability to import specialized function libraries, know as "modules", into your programs. These modules give you access to functions that are not normally available to you in Python.

#### Importing and Using Modules

To use a module we first have to import them into our own programs. Importing a module tells Python that we're going to need to access that module and all of the functions that it contains. In order to import a module into your program you first need to issue the `import` command - this command tells Python to load the module into memory and make available all of the functions in that module. Note that this command should happen at the very beginning of your program - the first few lines of your code should contain all of your "import" statements. Here's an example that imports the "math" module into a program:

```# ask Python to give us access to all of the functions in the "math" module
import math
```

Next, we will probably want to use the functions that exist within our newly imported module. We can do this using the period character (`.`) along with the name of the module to tell Python to run a function that exists within tha tmodule. We call this "dot syntax" - here's an example:

```# ask Python to give us access to all of the functions in the "math" module
import math

# now run the "sin" function inside of the "math" module
# note how we have to first tell Python to look inside of the "math" module
# then we use the "dot" character followed by the name of the function we want to access
x = math.sin(3.14159)
```

How do you know what functions are available inside of a module? One great way to explore the functions inside of a module is to refer to Python's online documentation website which is abailable at http://docs.python.org/3/. This page contains everything you need to know about how Python works, but if you're interested in learning more about a specific module you can click on the Global Module Index link and then scroll down to the module you are interested in. If you look at the documentation for the Math Module, you'll notice that it provides a lot of mathematical functions and constants, including:

• `math.sin`: computes the sine of a floating point number (returns a float)
• `math.radians`: converts degrees to radians (returns a float)
• `math.pi`: the constant PI computed to 15 decimal places

If you're using IDLE in "Interactive" mode you can also access the documentation straight from there by running the following command:

```help("modules")     # gets a list of available modules on your system
help("math")        # gets the documentation for the Math module
```

#### The Math Module

The `math` module contains a number of math-related functions and "constants" (read-only variables that you often need to use, such as the number Pi). Here are a few examples:

Sample Program: This program demonstrates how the "math" module can be imported and used in a Python program. Click the "Run" button to see the program in action or download a copy.

Sample Program: This program uses a number of "nested" `if` statements to convert a numeric grade into a letter grade. Click the "Run" button to see the program in action or download a copy.

#### The Random Module

Random numbers are often used in computer programs to give your programs the ability to make their own decisions. For example, let's say you were writing a program to play a game of Rock-Paper-Scissors with the user. We could easily ask the user which symbol they wanted to play using the `input` function, but how can the computer pick its symbol? One answer would be to have the computer pick a random number between 1 and 3. If the computer picks 1, then we can say that it picked 'Rock' - if it picked 2, 'Paper' - and if it picked 3, 'Scissors'. By ascribing meaning to these numbers we can give our programs the illusion of being able to "think" for themselves!

Here are some common examples of how we could use random numbers in a Python program:

• To play a game of chance where the computer needs to throw some dice, pick a number, or flip a coin
• To shuffle a deck of playing cards
• To randomly place a new enemy character in a game
• To simulate possible rainfall amounts in a computerized model for estimating the environmental impact of building a dam
• For encrypting your banking session on the Internet

Python provides a Random module that helps with tasks like this. You can take a look at it in the documentation.

The easiest way to generate a random number is to use the `random.randint` function. This function requires two argumenst - a low bound and a high bound. It then returns a random integer within this range (inclusive of the end points) - here's an example:

```import random

# get a random number between 1 and 3
# it could be 1, 2 or 3 - the function will decide when it runs
num = random.randint(1,3)```

Here are a few sample programs that use the `random.randint` function:

Sample Program: This program demonstrates how the "random" module can be imported and used to generate a random integer. Click the "Run" button to see the program in action or download a copy.

Sample Program: This program demonstrates how a random number can be "converted" into another value (in this case, into a random color name). Click the "Run" button to see the program in action or download a copy.

If you need to generate a random floating point number you can use the `random.random` function. This function returns a floating point number in the range [0.0, 1.0) — the square bracket means "closed interval on the left" and the round parenthesis means "open interval on the right". In other words, 0.0 is a possibility, but all returned numbers will be strictly less than 1.0 (i.e. 1.0 will never occur). It is usual to scale the results after calling this method, to get them into a range suitable for your application (i.e. multiplying this number by 10 will generate a random between 0.0 and 10.0).

It is important to note that the Python random number generator is based on a deterministic algorithm which means that it is both repeatable and predictable. This is why we call this method of generating random number "pseudo-random" generator — the numbers that are generated are not really random at all - they are actually based off of a "seed" value which is usually determined by your computer's built in clock. Each time you ask for another random number, you’ll get one based on the current seed (the system clock), and the state of the seed (which is one of the attributes of the generator) will be updated. The good news is that each time you run your program, the seed value is likely to be different meaning that even though the random numbers are being created algorithmically, you will likely get random behavior each time you execute.

Programming Challenge: Write a program that generates a random die roll on a six sided die. Click the "Run" button to check your work, and click here to download the solution.

Programming Challenge: Extend the previous program to generate two die rolls. Imagine that these two values are being used to play a virtual game of "Craps" - in this game each die combination has a unique name as can be seen in the following chart (the top row shows the value that was rolled for the first die and the left-most column shows the value that was rolled for the second die):

1 2 3 4 5 6
1 Snake Eyes Ace Deuce Easy Four Five (Fever Five) Easy Six Natural or Seven Out
2 Ace Deuce Hard Four Five (Fever Five) Easy Six Natural or Seven Out Easy Eight
3 Easy Four Five (Fever Five) Hard Six Natural or Seven Out Easy Eight Nine (Nina)
4 Five (Fever Five) Easy Six Natural or Seven Out Hard Eight Nine (Nina) Easy Ten
5 Easy Six Natural or Seven Out Easy Eight Nine (Nina) Hard Ten Yo (Yo-leven)
6 Natural or Seven Out Easy Eight Nine (Nina) Easy Ten Yo (Yo-leven) Boxcars

Your program should generate two die values, display the output along with the name of the roll. Hint: there are many repeating names in the table above! Use this information to your advantage!

For the purpose of this program you can generate two numbers between 1 and 3 (otherwise you would be typing all day!) - feel free to try and implement two six sided die rolls if you have the time though.

#### Alternate Import Option

The preferred method of importing a module into your program is to use the import command at the top of your program - you can then use "dot syntax" along with the name of your module to access functions organized within that module. However, there is another way to access modules which is sometimes used - this way is generally frowned upon as it clutters your programs namespace (what functions and data are defined in the current environment), but you should be aware of it as you may see it used elsewhere.

Instead of importing the module, you can import specific items into your programs namespace. The syntax is one of the following:
`from MODULE_NAME import ITEM_NAME`
`from MODULE_NAME import ITEM_NAME,ITEM_NAME,...`
`from MODULE_NAME import *`

This last option uses what we call a wildcard. A wildcard is a character that means it can match anything, on most systems that character is the asterisk (`*`). If you use the wildcard you're importing all the items from the entire module.

Here are some examples:

```# import all of the functions from the "random" module
from random import *

# call the "randint" function - note how we don't need to call it using
# the module name (i.e. random.randint(1,10) can be written as randint(1,10)
print(randint(1,10))
```
```# import just two functions from the "math" module
from math import pow,sqrt

# now we can call these functions without prefacing them with the "math." prefix
print(pow(2,16))
print(sqrt(16))
```

### Color in Turtle Graphics

Note that the graphics techniques presented in this section will not run correctly using our web-based coding environment. To try any of the code samples included below simply launch IDLE on your own computer and run the code locally.

Now that you know a little more about how modules work in Python we can go a little deeper into exploring how Turtle Graphics can be used to construct images ...s

#### Adjusting the Pen Size

You can adjust the size of the lines that your turtle cursor produces by using the `pensize` function. This function accepts a single float as an argument to describe how thick you want your lines to be drawn. For example, if you'd like to draw a very thin line to the screen you could call the `pensize` function as follows:

```# make the turtle graphics functions available
import turtle

# setup our canvas
turtle.setup(500,500)

# set our pen size to be very thin
turtle.pensize(0.1)

# draw a line
turtle.forward(100)```

... and to draw a very thick line you could do the following:

```# ... code continued from above ...

# set our pen size to be very thick
turtle.pensize(10)

# draw a line
turtle.forward(100)```

Here's a sample program that shows how the `pensize` function works. The drawing that will be produced from this program is also displayed below.

Demonstration of the `pensize` function

```# make the turtle graphics module available
import turtle

# set up our graphical canvas
# width = 500, height = 500
turtle.setup(500, 500)

# move to the top left side of the screen
turtle.penup()
turtle.goto(-50, 90)
turtle.pendown()

# draw a very thin line
turtle.pensize(0.1)
turtle.forward(100)

# move back to the left side of the screen
# and a little further down
turtle.penup()
turtle.goto(-50, 50)
turtle.pendown()

# thicker line
turtle.pensize(2)
turtle.forward(100)

# move back to the left side of the screen
# and a little further down
turtle.penup()
turtle.goto(-50, 0)
turtle.pendown()

# thicker line
turtle.pensize(7)
turtle.forward(100)

# move back to the left side of the screen
# and a little further down
turtle.penup()
turtle.goto(-50, -50)
turtle.pendown()

# thicker line
turtle.pensize(20)
turtle.forward(100)```

#### Setting the Pen Color

By default your turtle will draw solid black lines to the canvas. You can change this behavior by calling the `pencolor` function. The easiest way to use this function is to call it using a single String which represents the desired color of your pen. The turtle module understands most basic color names, such as "yellow", "red" and "green", along with some fairly non-standard names such as "wheat", "snow" and "mint cream"! A full list of supported color names can be found here.

Here's the same sample program as above (using `pensize`) with the addition of color:

Demonstration of the `pencolor` function

```# make the turtle graphics module available
import turtle

# set up our graphical canvas
# width = 500, height = 500
turtle.setup(500, 500)

# move to the top left side of the screen
turtle.penup()
turtle.goto(-50, 90)
turtle.pendown()

# draw a very thin line
turtle.pensize(0.1)
turtle.forward(100)

# move back to the left side of the screen
# and a little further down
turtle.penup()
turtle.goto(-50, 50)
turtle.pendown()

# set the pen color to red
turtle.pencolor("red")

# thicker line
turtle.pensize(2)
turtle.forward(100)

# move back to the left side of the screen
# and a little further down
turtle.penup()
turtle.goto(-50, 0)
turtle.pendown()

# set the pen color to blue
turtle.pencolor("blue")

# thicker line
turtle.pensize(7)
turtle.forward(100)

# move back to the left side of the screen
# and a little further down
turtle.penup()
turtle.goto(-50, -50)
turtle.pendown()

# set the pen color to yellow
turtle.pencolor("yellow")

# thicker line
turtle.pensize(20)
turtle.forward(100)```

#### Drawing Filled Shapes

Turtle Graphics is referred to as a "vector" graphics library. This means that shapes are described based on two properties - their outlines (referred to as "strokes") and their interiors (referred to as "fills"). So far we have been describing shapes only in terms of their "stroke" via the `pensize` and `pencolor` functions.

We can also ask Python to color the interior of our shapes by using a three new functions. Before we begin, let's drawa simple square using a red stroke color:

```# make the turtle graphics module available
import turtle

# also make the random module available
import random

# set up our graphical canvas
# width = 500, height = 500
turtle.setup(500, 500)

# set up our pen
turtle.pencolor("red")
turtle.pensize(5)

# draw a square
turtle.forward(100)
turtle.right(90)
turtle.forward(100)
turtle.right(90)
turtle.forward(100)
turtle.right(90)
turtle.forward(100)
turtle.right(90)```

In order to fill the interior of our square we need to tell Python what color to use as the "fill" for the shape. We can do that by calling the `fillcolor` function, like this:

`turtle.fillcolor("yellow")`

However, this only tells Python what color to use - it doesn't tell the system to actually begin filling the shape. To do this we have to call two additional functions - one of these functions tells Python to start filling a shape and ther other one tells the system that we are done drawing our shape and it's ready to be filled in. These functions, called `begin_fill` and `end_fill` are called before and after we draw our desired shape. Here's the code above with these two functions in place:

```# make the turtle graphics module available
import turtle

# also make the random module available
import random

# set up our graphical canvas
# width = 500, height = 500
turtle.setup(500, 500)

# set up our pen
turtle.pencolor("red")
turtle.pensize(5)

# set up our fill color
turtle.fillcolor("yellow")

# tell Python to start filling
turtle.begin_fill()

# draw a square
turtle.forward(100)
turtle.right(90)
turtle.forward(100)
turtle.right(90)
turtle.forward(100)
turtle.right(90)
turtle.forward(100)
turtle.right(90)

# tell Python that are we are finished filling
turtle.end_fill()```

A filled shape using the `pencolor`, `fillcolor`, `begin_fill` and `end_fill` functions

Note that `begin_fill` and `end_fill` are like "bookends" - you need to include them above and below the lines of code that you're writing to render the interior of a shape.

#### Graphics Programming Challenges

Programming Challenge: Write a program that asks the user for a stroke color and a fill color. Then draw a square on the screen using the supplied values.

If you'd like to view the solutions download a copy.

Programming Challenge: Extend the previous program to limit the user to only supplying the values "yellow", "red", "green" or "blue". If they supply an invalid color you can print an error message and end the program. Hint: you can call `turtle.bye()` to close the turtle canvas window.

If you'd like to view the solutions download a copy.

### Quiz

Now that you've completed this module, please visit our NYU Classes site and take the corresponding quiz for this module. These quizzes are worth 5% of your total grade and are a great way to test your Python skills! You may also use the following scratch space to test out any code you want.

### Feedback

Tell us what you thought about this module (it's anonymous).
How helpful did you find this module on a scale of 1-5:
Which resource(s) in this module did you find the most helpful (check all that apply):