Chapter 5 – Conditionals and recursion

Hi there,

The tip to read the chapter once (and taking notes on where I might find some obstacles) and then read it again a second time helped me tremendously.

The impression of “déjà vu” makes my second reading far more efficient. I am aiming to pick-up some speed with this reading tactic.

5.1 Modulus operator

A couple of months ago, I had to refresh my memory in order to explain the concept of remainder. However, I never thought that this concept would be helpful learning Python as well.

Wikipedia provides a full and comprehensive explanation of the modulo operation. I recommend to read it.

Basically, a remainder is the number that is left when you divide two numbers that are not multiples.

Modulo operation finds the remainder of a division

Modulo operation finds the remainder of a division

In Python, the modulus operator is the percent sign %.

If the remainder of x divided by y is zero, then we infer that x is divisible by y or x is a multiple of y.

Multiple and Factors

Multiple and Factors

The book provides a clear example:

>>> quotient = 7/3
>>> print quotient
2
>>> remainder = 7 % 3
>>> print remainder
1

5.1 Boolean expressions

A Boolean expression is an expression that is either true or false.

The operator == compares two operands and verify whether they are equal or not.

>>> 5 == 5
True

>>> 5 == 6
False

If we verify the type of True and False, we discover that they belong to the type bool.

>>> type (True)<type ‘bool’>

>>> type (False)
<type ‘bool’>

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

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.

x = y    # x gets the value of y

versus

x == y    # x is equal to y

Who is Boole? George Boole was an English mathematician, philosopher and logician of the 19th century. You may click on his name in order to find out more about him.

5.3 Logical operators

  • and
    x > 0 and x < 10 is true if both relations are true
  • or
    x > 0 or x < 10 is true if either relation is true
  • not
    The not operator negates a Boolean expression.
    not ( x < 10 ) is true if x is greater than 10 and it is false if x is less than 10.

5.4 Conditional execution

This is where the fun starts.

Conditional statements provide Python users with the ability to to check conditions and change the behaviour of the program accordingly.

Conditional execution

Conditional execution

 

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

As we advance and write more elaborate functions and eventually programs, there is a useful statement called pass which does nothing. It is a place keeper for code to be written.

For instance:

if x < 0:    pass       # code to be written at a later time

5.5. Alternative execution

The alternative execution provides two (2) possibilities and the condition determines which one gets executed.

This is a second form of the if statement. The syntax looks like this:

if x % 2 == 0:    print ‘x is even’
else:
print ‘x is odd’

The condition can either be true or false. So only one alternative will be executed.

The alternatives are called branches, because they are branches in the flow of execution.

5.6 Chained conditionals

When we have more than two possibilities, then we need more than two branches. Chained conditionals enable us to express a computation with more than two alternatives.

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’

As soon as Python finds a True Boolean expression, then the branch will be executed.

elif

  • It is the abbreviation of “else if”.
  • There is no limit on the number of elif statements.

else

  • If there is an else statement, it has to be at the end.
  • The else statement is optional.

Python’s flow of execution:

Each condition is checked in order. If the first is false, the next is checked, and so on. If one of them is true, the corresponding branch executes, and the statement ends. Even if more than one condition is true, only the first true branch executes.

5.7 Nested conditionals

Conditionals can also be nested within another. This concept reminded me of the nested functions we saw on Chapter 3 and the Matryoshka image.

Python Nested Conditionals

Python Nested Conditionals

Love-Hate relationship with nested conditionals:

Love: Indentation provides nested conditionals with an apparent structure.

Hate: Beware, it is easy to get frustrated trying to find indentation bugs.

The author, Allen B. Downey points out that nested conditionals become difficult to read at a glance.

Logical operators often provide a way to simplify nested conditionals.

Nested conditionals versus logical operators

Nested conditionals versus logical operators

NOTE: In this chapter, the author used the word trichotomy. I looked up in Wikipedia and it means “splitting into three parts”.

5.8 Recursion

In the Python world, a function can call another function and a function can call itself as well.

A function that calls itself is recursive; the process is called recursion.

Recursive function with a return statement

Recursive function with a return statement

5.9 Stack diagrams for recursive functions

Stack diagrams are helpful to illustrate a function call or a recursive function.

Every time a function gets called, Python creates a new function frame, which contains the function’s local variables and parameters. For a recursive function, there might be more than one frame on the stack at the same time.

Think Python: Exercise 5.1

Think Python: Exercise 5.1

Exercise 5.2

Let us make a break and laugh a bit.

When I read this exercise I had the impression I was in the same situation as this:

School and Homework verus Exam questions

School and Homework verus Exam questions

Source: So Relatable

Here is the question:

Write a function called do_n that takes a function object and a number, n, as arguments, and that calls the given function n times.

What blocked me was the expression “function object“. So, I had to go back to Chapter 3 (p.22 and p. 29) to recall the definition.

A function object is a value you can assign to a variable or pass as an argument. For example, do_twice is a function that takes a function object as an argument and calls it twice:

def do_twice ( f ):
f ( )

f ( )

Here is an example that uses do_twice to call a function named print_spam twice.

def print_spam( ):    print ‘spam’

do_twice ( print_spam )

Inspiring me from this reference, here is what I found:

>>> def do_n (f, n):
…     if n <= 0:
…             return
…     else:
…             f()
…             do_n(f, n-1)

>>> def lyrics ():
…     print “I’m singing in the rain ”

>>> do_n (lyrics, 3)
I’m singing in the rain
I’m singing in the rain
I’m singing in the rain
>>>

5.10 Infinite recursion

If a recursion never reaches a base case, it goes on making recursive calls forever, and the program never terminates. This is known as infinite recursion, and it is generally not a good idea.

Once Python reaches 1000 recurse frames on the stack it will report an error.

5.11 Keyboard input

We will begin to write code blocks that require the user to interact.

In Python 2: raw_input function

In Python 3: input function

When this function is called, the program stops and waits for the user to type something. When the user presses “Enter“, the program resumes and raw_input returns what the user typed as a string.

When you ask the user for some input. It is best to state the question. For instance:

>>> sports = raw_input (‘Do you play any volley-ball or football?’\n’)
volleyball

>>> print sports
volleyball

The sequence \n at the end of the prompt represents a newline, which is a special character that causes a line break. That is why the user’s input appears below the prompt.

By default, the user’s answers are considered stings. However, we can change that like this:

>>> prompt = “What is the speed of sound in meters per second in dry air?\n”
>>> speed_sound = raw_input(prompt)
What is the speed of sound in meters per second in dry air?
343.2

>>> speed_sound
‘343.2’
>>> float(speed_sound)
343.2
>>>

5.12 Debugging

Python provides a hints for debugging such as:

  • What kind of error it was, and
  • Where it occurred.

Beware of these mistakes because they are a bit tricky to find:

  • whitespace errors: spaces and tabs are invisible to Python
  • runtime errors: watch for integer numbers versus floating numbers when dividing.

Python can indicate the line where the error occurred. However, verify the previous lines as well in order to correct the error more quickly.

So, this is it for the theory of chapter 5!

 

It does not matter how slowly you go, so long as you do not stop — Confucius, Chinese philosopher (551 BC – 479 BC)

 

***

Acknowledgments :

These notes represent my understanding from the book Think Python: How to Think Like a Computer Scientist written by Allen B. Downey.

Part of the chapter is transcribed and all the quotes unless specified otherwise come directly from his book.

Thank you Professor Downey for making this knowledge available.

 

Also, I would like to thank the open source community for their valuable contribution in making resources on programming available.

Thank you

Chapter 3: Functions (Part III)

New terms from chapter 3 (Think Python: Think Like a Computer Scientist) – PART III

At this stage, we can define our own functions.

For instance, we defined the function ‘print_bruce’ which prints twice the parameter ‘bruce’.

>>> def print_twice(bruce):          # Here we define the function ‘print_twice’. The function has one (1) parameter: ‘bruce’.
…     print bruce                                 # The function will print the parameter ‘bruce’ two (2) times (or twice).
…     print bruce

>>>

Also, we can nest one function into another. I think of it like a computer programming Matryoshka.

For example:

>>> def sing_song (part1, part2): # Here we define the function ‘sing_song’. The function has two (2) parameters: ‘part1’ and ‘part2’
…     cat = part1 + part2                    # The variable ‘cat’ gets the value of the concatenation of parameter 1 and parameter 2.
…     print_twice (cat)                       # Here the function ‘print_twice’ is called and uses variable ‘cat’ as an argument.

>>>

Let us see what happens when we call the function ‘sing_song’ with the arguments: “Jingle” and “Bell”

>>> sing_song (“Jingle”, “Bell”)
JingleBell
JingleBell

Matryoshka dolls - Python nested functions

Matryoshka dolls – Python nested functions

Here is a more complete definition of what I am trying to convey :

In computer programming, a nested functions […] is a function which is lexically (textually) encapsulated within another function, with lexical scope […]

Due to nesting, the scope of the nested function is inside the enclosing function. This means that it can access local variables and other local functions in the enclosing function, while all of this is invisible outside the enclosing function.

Source: Wikipedia: Nested Function

3.10 Stack Diagrams

Stack diagrams are illustrations that can help us track who is who in nested functions and what sequence the program will follow in order to execute functions.

Stack diagrams show the value of each variable, but they also show the function each variable belongs to.

Each function is represented by a frame. A frame is a box with the name of a function beside it and the parameters and variables of the function inside it.

The frames are arranged in a stack that indicates which function called which, and so on.

Here is an example:

What happens if an error occurs during a function call ?

Python will help us trace the error back to its origin ( __main__ ).

– Traceback : Is a list that will help you find the error. It will provide:

  • the program file the error occurred in,
  • the line of code that caused the error, and
  • the functions that were executing at the time of the error.

3.11 Fruitful functions and void functions

– Fruitful functions: Allen B. Downey, Think Python’s author refers to fruitful functions, all the functions that will yield results (or return a value).

For instance, try this in the Python Shell (interactive mode):>>> import math     # First, you need to import that module math.
>>> math.sqrt(4)     # Then, let us remember the format to use in order to use a function from a module:  module . function (argument or variable)
2.0                               # This is the result that Python returns.
>>>

– Void functions: Void functions are functions, like ‘print_twice’ (that we defined earlier), that perform an action (either display something on the screen or perform some other action). However, they do not return a value.

For instance, we defined the function ‘print_twice’. The function is meant to perform the action of printing twice the parameter ‘bruce’.

In interactive mode:
Python will display the result of a void function if and only if we call a function in interactive mode.
In script mode:
When we call a fruitful function all by itself in script mode, the return value is lost forever if we do not store or display the result.
For instance:
>>> def print_twice(bruce):
…     print bruce
…     print bruce

>>> result = print_twice(‘Bing’)
Bing
Bing
>>> print result
None
>>>
It is important to note that although Python displayed the value of result earlier, the result displayed:
Bing
Bing
is lost forever since we did not store it anywhere.
In order to transmit this idea Python created the notion of ‘None’. It is a special value that has its own type.
>>> print type(None)
<type ‘NoneType’>
>>>

3.12 Why divide a program into functions?

  • By using functions, we are able to group statements. Thus, reading and debugging the program becomes easier. Just like playing with Lego blocks, a long program can be divided into functions (Lego blocks) that allow us to debug functions one at a time and the assembled them into a working whole.
  • By using functions, we can eliminate repetitive code. Therefore, functions are useful to make a program concise.
  • Well-designed functions can be useful for many programs.

3.13 Importing with from

We can use functions in modules in three different ways:

  • Import a module object in Python:

If you import math, you get a module object named math. The module object contains constants like pi and functions like sin and exp.

>>> import math
>>> print math
<module 'math' (built-in)>
>>> print math.pi          #Remember the format: module . function
3.14159265359
  • Import an object from a module in Python

>> from math import pi
Now you can access pi directly, without dot notation.

>>> print pi
3.14159265359
  • Import all objects from a module in Python
>>> from math import *

The advantage of importing everything from the math module is:
that your code can be more concise.

The disadvantage is:
that there might be conflicts between names defined in different modules, or between a name from a module and one of your variables.

3.14 Debugging

Python uses whitespaces indentation in order to delimit code blocks, a feature also termed the “off-side rule”.  An increase in indentation comes after certain statements; a decrease in indentation signifies the end of the current block.

Source: Wikipedia: Python Programming Language

Indentation bugs are difficult to find because they are invisible. The solution is to find a text editor that will manage indentation for you.

The text editor I use is “Sublime Text version 2”. So, I use tabs while writing code. However, with Sublime Text 2, I have to save my program before I run it.

Think Python’s author, Allen B. Downey provides a great advice to find errors in a particular code block. Here it is:

Debugging can take a long time if you keep running the same, incorrect, program over and over!

Make sure that the code you are looking at is the code you are running. If you’re not sure, put something like print ‘hello’ at the beginning of the program and run it again. If you don’t see hello, you’re not running the right program!

Think Python, p. 28

 

***

Acknowledgments :

These notes represent my understanding from the book Think Python: How to Think Like a Computer Scientist written by Allen B. Downey.

Part of the chapter is transcribed and all the quotes unless specified otherwise come directly from his book.

Thank you Professor Downey for making this knowledge available.

 

Also, I would like to thank the open source community for their valuable contribution in making resources on programming available.

Thank you