<jupyter_start><jupyter_text>Conditionals and Recursion- `if` statement    - executes code depending on the state of the program Floor division and modulusThe **floor division** operator, //, divides two numbers and rounds down to an integer.Suppose you have a movie with a runtime of 105 minutes. You might want to know how long that is in hours.Conventional division returns a floating-point<jupyter_code>minutes = 105
minutes / 60<jupyter_output><empty_output><jupyter_text>But we don’t normally write hours with decimal points. Floor division returns the integer number of hours, rounding down:<jupyter_code>hours = minutes // 60
hours<jupyter_output><empty_output><jupyter_text>**Modulus operator**, %, which divides two numbers and returns the remainder.<jupyter_code>remainder = minutes % 60
remainder
def movie_time(minutes):
    """Converts movie time from minutes 
    to hours minutes.
    Output:
    =========
    
    X hrs Y mins
    
    """
    hrs = minutes // 60
    mins = minutes % 60
    print(str(hrs) + ' hrs ' + str(mins) +' mins')
movie_time(105)<jupyter_output>1 hrs 45 mins<jupyter_text>Boolean expressionsA boolean expression is an expression that is either true or false. The following examples use the operator `==`, which compares two operands and produces `True` if they are equal and False otherwise:<jupyter_code>5 == 5
5 == 6
type(True)
type(False)<jupyter_output><empty_output><jupyter_text>The `==` operator is one of the relational operators; the others are:| Relational Operator | Description                     ||---------------------|---------------------------------|| x != y              | x is not equal to y             || x > y               | x is greater than y             || x < y               | x is less than y                || x >= y              | x is greater than or equal to y || x <= y              | x is less than or equal to y    |  Logical operatorsThere are three **logical operators**:     - and, or, and not.     The meaning of these operators is similar to their meaning in English.  For example, `x > 0` **and** `x < 10` is true only if x is greater than 0 and less than 10.<jupyter_code>5 > 0 and 5 < 10
20 > 0 and 20 < 10<jupyter_output><empty_output><jupyter_text>`n%2 == 0` **or** `n%3 == 0` is true if either or both of the conditions is true, that is, if the number is divisible by 2 or 3<jupyter_code>4 % 2 == 0 or 4 % 3 == 0
9 % 2 == 0 or 9 % 3 == 0
9 % 2 == 0 or 10 % 3 == 0<jupyter_output><empty_output><jupyter_text>the not operator negates a boolean expression, so **not** `(x > y)` is true if x > y is false, that is, if x is less than or equal to y.<jupyter_code>not (10 > 5)
(10 > 5)<jupyter_output><empty_output><jupyter_text>Conditional executionIn order to write useful programs, we almost always need the ability to check conditions and change the behavior of the program accordingly. **Conditional statements** give us this ability. The simplest form is the if statement:<jupyter_code>x = 10 
if x > 0:
    print('x is positive')<jupyter_output>x is positive<jupyter_text>The boolean expression after if is called the **condition**. If it is true, the indented statement runs. If not, nothing happens.`if` statements have the same structure as function definitions: a header followed by an indented body. Statements like this are called **compound statements**.  Alternative executionA second form of the if statement is “alternative execution”, in which there are two possibilities and the condition determines which one runs. The alternatives are called **branches**, because they are branches in the flow of execution.<jupyter_code>x = 10

if x % 2 ==0:
    print('x is even')
else:
    print('x is odd')

x = 9

if x % 2 ==0:
    print('x is even')
else:
    print('x is odd')<jupyter_output><empty_output><jupyter_text>Chained conditionalsSometimes there are more than two possibilities and we need more than two branches. `elif` is an abbreviation of “else if”. Exactly one branch will run. There is no limit on the number of elif statements. If there is an else clause, it has to be at the end, but there doesn’t have to be one.One way to express a computation like that is a **chained conditional**:<jupyter_code>x = 10
y = 11

if x < y:
    print('x is less than y')
elif x > y:
    print('x is greater than y')
else:
    print('x and y are equal')
x = 12
y = 11

if x < y:
    print('x is less than y')
elif x > y:
    print('x is greater than y')
else:
    print('x and y are equal')
x = 12
y = 12

if x < y:
    print('x is less than y')
elif x > y:
    print('x is greater than y')
else:
    print('x and y are equal')<jupyter_output><empty_output><jupyter_text>Nested conditionals- One conditional can also be nested within another. - The outer conditional contains two branches. - The first branch contains a simple statement. - The second branch contains another if statement, which has two branches of its own.     - Those two branches are both simple statements, although they could have been conditional statements as well.<jupyter_code>x = 12
y = 12

if x == y:
    print('x and y are equal')
else:
    if x < y:
        print('x is less than y')
    else:
        print('x is greater than y')
x = 12
y = 11

if x == y:
    print('x and y are equal')
else:
    if x < y:
        print('x is less than y')
    else:
        print('x is greater than y')
x = 10
y = 11

if x == y:
    print('x and y are equal')
else:
    if x < y:
        print('x is less than y')
    else:
        print('x is greater than y')<jupyter_output><empty_output><jupyter_text>Although the indentation of the statements makes the structure apparent, nested conditionals become difficult to read very quickly. **It is a good idea to avoid them when you can.**  RecursionIt is legal for one function to call another; it is also legal for a function to call itself. It may not be obvious why that is a good thing, but it turns out to be one of the most magical things a program can do.   What is recursion in Python?Recursion is the process of defining something in terms of itself.A physical world example would be to place two parallel mirrors facing each other. Any object in between them would be reflected recursively.<jupyter_code>def countdown(n):
    if n <= 0:
        print('Blastoff!')
    else:
        print(n)
        countdown(n-1)<jupyter_output><empty_output><jupyter_text>- If n is 0 or negative, it outputs the word, “Blastoff!” - Otherwise, it outputs n and then calls a function named countdown—itself—passing n-1 as an argument.<jupyter_code>countdown(5)<jupyter_output>5
4
3
2
1
Blastoff!<jupyter_text>Infinite recursion- **Infinite recursion** is when a recursion never reaches a base case, it goes on making recursive calls forever, and the program never terminates.In most programming environments, a program with infinite recursion does not really run forever. Python reports an error message when the maximum recursion depth is reached:<jupyter_code>def recursion():
    recursion()
recursion()<jupyter_output><empty_output><jupyter_text>Keyboard Input- Python provides a built-in function called `input` that stops the program and waits for the user to type something. - When the user presses Return or Enter, the program resumes and input returns what the user typed as a string.<jupyter_code>text = input()
text
number = input('Pick a number between 1 and 3:\n')
number
int(number)<jupyter_output><empty_output><jupyter_text>What if they typed out the digits instead?<jupyter_code>number = input('Pick a number between 1 and 3:\n')
int(number)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09225092250922509, 'fraction_numerical': 0.01620980495519241, 'mean_word_length': 3.607771706132362, 'pattern_counts': {'":': 0, '<': 74, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '16', 'dir': 'jupyter-structured-clean-dedup', 'id': '44841', 'license': 'MIT', 'n_tokens_mistral': 2330, 'n_tokens_neox': 2171, 'n_words': 1036, 'path': '00_python_basics/conditionals_recursion.ipynb', 'repo_name': 'markumreed/data_management_sp_2021', 'size': '7588'}