CIS 1051 - Temple Rome Spring 2023¶

Intro to Problem solving and¶

Programming in Python¶

LOGO

LOGO

Conditionals and Recursion¶

Prof. Andrea Gallegati

( tuj81353@temple.edu )

Floor Division and Modulus¶

The floor division operator // divides two numbers and rounds down to an integer.

For example, conventional division returns a floating-point number:

In [1]:
minutes = 105
minutes / 60
Out[1]:
1.75

Suppose you want to know the run time of a movie – that is 105 minutes – in hours: we don’t normally write hours with decimal points.

Floor division returns the integer number of hours, dropping the fraction part.

In [6]:
minutes = 105
hours = minutes // 60
hours
Out[6]:
1

To get the remainder, you could subtract off one hour in minutes:

In [7]:
remainder = minutes - hours * 60
remainder
Out[7]:
45

... or simply use the modulus operator % which divides two numbers and returns the remainder:

In [8]:
remainder = minutes % 60
remainder
Out[8]:
45

The modulus operator is more useful than it seems, for example:

  • to check whether a number is divisible by another: if x % y is zero, then x is divisible by y.
  • to extract the right-most digit or digits from a number: x % 10 yields the right-most digit of x and x % 100 yields the last two digits.

... using Python2 division works differently.

The division operator / performs floor division if both operands are integers and floating-point division if either operand is a float.

Boolean Expressions¶

are expressions that are either true or false.

The following examples use the operator ==, which compares two operands and produces True if they are equal and False otherwise:

In [9]:
5 == 5
Out[9]:
True
In [10]:
5 == 6
Out[10]:
False

True and False are special values that belong to the type bool: they are not strings!

In [13]:
print(type(True))
<class 'bool'>
In [14]:
print(type(False))
<class 'bool'>

The == operator is one of the relational operators:

x == y               # x is equal to y
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

Although they seems familiar, Python symbols are different from the mathematical symbols.

... a common error is to use a single equal sign (=) instead of a double equal sign (==).

Remember that = is an assignment operator and == is a relational operator.

Logical Operators¶

There are three logical operators, whose semantics (meaning) is similar to the one in English:

  • and
  • or
  • not
In [18]:
x = 7

x > 0 and x < 10
Out[18]:
True

is true only if x is greater than 0 and less than 10.

In [17]:
n = 9

n%2 == 0 or n%3 == 0
Out[17]:
True

is true if either or both of the conditions are true, i.e. if the number is divisible by 2 or 3.

In [19]:
y = 8

not (x > y)
Out[19]:
True

is true if x is less than or equal to y (the not operator negates a boolean expression).

... strictly speaking, the operands of the logical operators should be boolean expressions, but Python is not very strict.

Any nonzero number is interpreted as True:

In [15]:
42 and True
Out[15]:
True

This flexibility can be useful, but there are some subtleties to it that might be confusing.

You might want to avoid it (unless you know what you are doing).

Conditional Execution¶

To write useful programs, we almost always need to change the program behavior accordingly to different conditions.

Conditional statements give us this ability and it is that simple as this if statement:

In [20]:
if x > 0:
    print('x is positive')
x is positive

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.

There is no limit on the number of statements that can appear in the body, but there has to be at least one.

Occasionally, it is useful to have a body with no statements (e.g. placeholders for code you haven’t written yet).

In that case, you can use the pass statement, which does nothing.

In [23]:
if x < 0:
    pass          # TODO: need to handle negative values!

Alternative Execution¶

another form, where there are two possibilities and the condition determines which one runs.

In [24]:
if x % 2 == 0:
    print('x is even')
else:
    print('x is odd')
x is odd

The alternatives are called branches in the flow of execution.

  • If the remainder – dividing by 2 is 0 – then x is even: the program displays an appropriate message.
  • If the condition is false, the second set of statements runs.

The condition must be true or false, thus exactly one of the alternatives will run.

Chained Conditionals¶

If there are more than two possibilities and we need more than two branches:

In [26]:
if   x > y:
    print('x is greater than y')
elif x < y:
    print('x is less than y')
else:
    print('x and y are equal')
x is less than y

elif is an abbreviation of else if.

Again, exactly one branch will run.

There's no limit on the number of elif statements.

The else clause (if one) has to be at the end, but there doesn’t have to be one.

In [30]:
choice = 'd'

if   choice == 'a':
    draw_a()
elif choice == 'b':
    draw_b()
elif choice == 'c':
    draw_c()

... conditions are checked in order. If one of them is true, the corresponding branch runs and the statement ends.

Even if more than one condition is true, only the first true branch runs!

Nested Conditionals¶

One conditional can also be nested within another.

Thus, previous examples could be rewritten like this:

In [31]:
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 is less than y
  • The outer conditional contains two branches:
    1. The first branch contains a simple statement.
    2. The second branch contains another if statement, which has two branches of its own:
      1. a simple statement
      2. another simple statement

Those two branches are both simple statements, although they could have been conditional statements as well!

Indentation makes the structure apparent, but nested conditionals become difficult to read very quickly.

It is a good idea to avoid them when you can!

Logical operators often provide a way to simplify nested conditional statements

In [ ]:
if 0 < x:
    if x < 10:
        print('x is a positive single-digit number.')

... that can be rewritten using a single conditional:

In [ ]:
if 0 < x and x < 10:
    print('x is a positive single-digit number.')

The print statement runs if and only if we make it past both conditionals: same effect with the and operator.

For this kind of condition, Python provides a more concise option ;)

In [38]:
if 0 < x < 10:
    print('x is a positive single-digit number.')
x is a positive single-digit number.

Recursion¶

It 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.

In [40]:
def countdown(n):
    if n <= 0:
        print('Blastoff!')
    else:
        print(n)
        countdown(n-1)

If n is 0 or negative, it outputs the word, “Blastoff!”

Otherwise, it outputs n and calls the countdown function (i.e. itself) passing n-1 as argument.

What happens if we call a function like this?

In [41]:
countdown(3)
3
2
1
Blastoff!

The execution of countdown begins with n=3, but since n is greater than 0, it outputs the value 3 and then calls itself again...

Keyboard Input¶

Programs we have written so far accept no input from the user.

They just do the same thing every time.

Python provides a built-in function called input that:

  • stops the program
  • waits for the user to type something
  • as the user presses Return or Enter, the program resumes
  • input returns what the user typed as a string.

In Python2, the same function is called raw_input.

>>> text = input()
What are you waiting for?
>>> text
What are you waiting for?

Before getting input from the user, it's a good idea to print a prompt telling the user what to type.

... input can take a prompt as an argument!

>>> name = input('What...is your name?\n')
What...is your name?
Arthur, King of the Britons!
>>> name
Arthur, King of the Britons!

The sequence \n at the end of the prompt represents a newline, which is a special character that causes a line break.

That’s why the user’s input appears below the prompt.

If you want the user to type an integer, try to convert the return value to int:

>>> prompt = 'What...is the airspeed velocity of an unladen swallow?\n'
>>> speed = input(prompt)
What...is the airspeed velocity of an unladen swallow?
42
>>> int(speed)
42

But if the user types something other than a string of digits, you get an error:

>>> speed = input(prompt)
What...is the airspeed velocity of an unladen swallow?
What do you mean, an African or a European swallow?
>>> int(speed)
ValueError: invalid literal for int() with base 10

We will see how to handle this kind of error later.