Hi there,

In this chapter, Allen B. Downey, the author draws attention to the fact that all the functions we have written so far are void (their return value is *None*).

It was a disappointing revelation. I thought I was already coding elaborate functions; specially with all the hair pulled on exercise 4.3.

By the way, last year I took an “Intro to Python” class with Girl Develop It . It was a hands on class. The Pythonista in charge, Bethany cleverly demonstrated how to jump into coding. Nevertheless, one of the notions I stumbled upon was the “return” concept. The idea of a “phantom” return that was somehow kept on hold without manifesting itself was a bit confusing.

Fortunately, Allen B. Downey, the author dedicates a whole chapter to fully explain return values and its ramifications.

**6.1 Return values**

[… ]in a fruitful function the

returnstatement includes an expression. This statement means: “Return immediately from this function and use the following expression as a return value”

def area(radius):

temp = math.pi * radius**2

return temp

This function returns the area of a circle with the given radius.

Temporary variable: A variable used to store an intermediate value in a complex calculations.

In addition, let us consider this function including an alternative conditional:

[It is important to note that] as soon as a return statement executes, the function terminates without executing any subsequent statements.

Code that appears after a

returnstatement, or any other place the flow of execution can never reach, is calleddead code.

None: A special value returned by functions that have no return statement or a return statement without an argument.

In order to excel as programmers, we should be able to foresee all possible paths that the program might take so it can hit a *return* statement.

In the example above, our function would be stuck if we asked for the absolute value of 0 (zero). We would get the return value *None*.

**Exercise 6.1** Write a *compare* function that :

- returns 1 if
*x*> y, - returns 0 if
*x*==*y*, and - returns -1 if
*x*<*y*.

P.S. Have you ever wondered what is the difference between *print* statement and *return* statement in Python? For those who know the difference, this question might seem trivial. However, this is a perfectly pertinent question to ask.

When we use Python in interactive mode (Terminal running the Python interpreter), here are the scenarios:

**Scenario no1 – Interactive mode**

- Code block #1: using the
*return*statement

>>> def absolute_value(x):

… if x < 0:

… return -x

… if x > 0:

… return x

…

>>> absolute_value(3)

3

>>>

**Scenario no2 – Interactive mode**

- Code block #2: using the
*print*statement

>>> def absolute_value(x):

… if x < 0:

… print -x

… if x > 0:

… print x

…

>>> absolute_value(3)

3

>>>

Both code blocks give the exact same result. So, what is the difference? We can clearly see the difference using the script mode.

When we write code in script mode (with Sublime Text for instance), here are the scenarios:

**Scenario no1 – Script mode**

- Code block #1: using the
*return*statement

def absolute_value(x):

if x < 0:

return -x

if x > 0:

return x

absolute_value(3)

Since we wrote the code in Sublime Text (and saved it as a “abs_val.py” document for instance), we must verify the the outcome using the Terminal.

We travel in our terminal to find our “abs_val.py” document.

MacBook-Air-xxxx:Desktop xxxx$ python abs_val.py

The outcome will be … humm, nothing. Nothing appears on our screen.

If this is the first time it happens to you, you might say: “My code block did not work!”.

The good news is that it DID work. On the bright side, your program worked and the function evaluated abs_val(3). However, we did not ask our code block to print anything. Although the computation was correctly performed, nothing was demonstrated in the terminal.

**Scenario no2 – Script mode**

- Code block #2: using the
*print*statement

def absolute_value(x):

if x < 0:

print -x

if x > 0:

print x

absolute_value(3)

Again, we travel in our terminal to find our “abs_val.py” document.

MacBook-Air-xxxx:Desktop xxxx$ python abs_val.py

This time, we will see:

3

Which is the answer of abs_val(3).

To recapitulate, on the one hand, the *return* statement will execute the function and *return* the value without printing it (if you are in script mode). On the other hand, the *print* statement will print the *return* value you obtained from executing your function.

Does this help?

If you can explain it better, let me know as well.

**6.2 Incremental development**

As we write more elaborate programs, **incremental development** can be a way to tackle daunting programming challenges.

The goal of incremental development is to avoid long debugging sessions by adding and testing only a small amount of code at a time.

In order to demonstrate the reasoning behind incremental development, let us create a function capable of calculating the distance of two points.

**Step 1**** :** If we follow George Polya’s method, the first step is to understand the problem or just the equation we are trying to translate into coding.

So, the Pythagorean theorem states that the hypotenuse (*c*) to the power of two (2) is equal to the sum of the square of side *a* and the square of side *b*.

**c² = a² + b²**

**distance = ( ( x_{2} – x_{1} )^{2} + ( y_{2} – y_{1} )^{2} )^{1/2}**

NOTE: If you want to know how far the Pythagorean theorem can take you, I recommend to read *Why Does E=mc2?: And Why Should We Care?* written by Dr. Brian Cox and Professor Jeff Forshaw.

At this step we can establish the input (the parameters) and the output (that it the return value).

- Parameters: two points

m = (*x*,_{1}*y*)_{1}n

**=**(*x*,_{2}*y*)_{2}

- Return value: the distance from point m to point n

**Step 2**** : **Elaborate a plan (according to Polya’s problem solving strategy).

The plan is to use incremental development in order to build the code block that calculates the distance of two points (m and n).

**Step 3**** :** The third step is to carry out the plan:

- Incremental plan – step (
*i*): Start with a working program and make small incremental changes.

Verify that the function is syntactically correct.

>>> def distance (x1, y1, x2, y2):

… return 0.0

…

>>> distance (1, 2, 4, 6) *#By using simple arguments, we can test the function easily.*

0.0

>>>

- Incremental plan – step (
*ii*): Use temporary variables to hold intermediate values so you can display and check them.

Find the differences.

>>> def distance (x1, y1, x2, y2):

… dx = x2 – x1

… dy = y2 – y1

… print ‘dx is ‘, dx

… print ‘dy is ‘, dy

… return 0.0

…

>>> distance (1, 2, 4, 6)

dx is 3

dy is 4

0.0

>>>

[At this stage we know that] the function is getting the right arguments and performing the first computation correctly.

- Incremental plan – step (
*iii*): Use temporary variables to hold intermediate values so you can display and check them.

Compute the sum of the squares*dx*and*dy*:

>>> def distance (x1, y1, x2, y2):

… dx = x2 – x1

… dy = y2 – y1

… dsquared = dx**2 + dy**2

… print ‘dsquared is ‘, dsquared

… return 0.0

…

>>> distance (1, 2, 4, 6)

dsquared is 25

0.0

>>>

- Incremental plan – step (
*iv*): Compute the square root of dsquared in order to find the distance between point m and n.

>>> import math *#If you want to use the built-in function “sqrt” from Python, you must import the math module first.*

>>> def distance (x1, y1, x2, y2):

… dx = x2 – x1

… dy = y2 – y1

… dsquared = dx**2 + dy**2

… result = math.sqrt(dsquared)

… return result

…

>>> distance (1, 2, 4, 6)

5.0

>>>

NOTE: The “*print*” statements we wrote in step (*ii*) and (*iii*) are useful for debugging. If the function is working, we can condense the code block by removing them.

Scaffolding :Code that is used during program development but it not part of the final version.

**Step 4**** :** Once the program is working, you might want to remove some of the scaffolding or consolidate multiple statements into compound expressions. The goal is to balance conciseness and easily comprehension of the code.

George Polya suggests to answer this question: How could it be better?

**Exercise 6.2**

This function is the exact same as the function “distance (x1, y1, x2, y2)”.

**6.3 Composition**

Composition: is the ability to call one function from within another.

Step 1) Find the radius of the circle (which is the distance between two points).

Recall:

>>> def distance (x1, y1, x2, y2):

… dx = x2 – x1

… dy = y2 – y1

… dsquared = dx**2 + dy**2

… result = math.sqrt(dsquared)

… return result

…

>>>

radius = distance (xc, yc, xp, yp)

Step 2) Find the area of a circle with a radius.

Recall:

>>> def area (radius):

… return math.pi * radius**2

…

>>>

result = area (radius)

In order to link the distance function and the area function, remember that the *radius* is our distance formula.

>>> def circle_area (xc, yc, xp, yp):

… radius = distance (xc, yc, xp, yp) *#Consider the variable “radius” as a temporary variable*

… result = area (radius) *#Consider the variable “result” as a temporary variable*

… return result

…

>>> circle_area (1, 2, 4, 6)

78.53981633974483

>>>

“How could it be better?”

If we want to answer the question, we can make our code block more concise by composing the function calls as follows:

>>> def circle_area (xc, yc, xp, yp):

… return area (distance(xc, yc, xp, yp))

…

>>> circle_area (1, 2, 4, 6)

78.53981633974483

>>>

**6.4 Boolean functions**

Functions can return booleans, which is often convenient for hiding complicated test inside functions.

Let us consider this example:

>>> def is_divisible(x, y):

… if x % y == 0:

… return True

… else:

… return False

…

>>> is_divisible (8, 2)

True

>>> is_divisible (5, 3)

False

>>>

NOTE: By definition, the result of a Boolean expression is either True or False. Therefore, we can re-write the the function more concisely.

>>> def is_divisible (x, y):

… return x % y == 0

…

>>> is_divisible (8, 2)

True

>>> is_divisible (5, 3)

False

>>>

Boolean functions are often used in conditional statements.

**Exercise 6.3** Write a function is_between (x, y, z) that returns True if x ≤ y ≤ z or False otherwise.

>>> def is_between (x, y, z):

… return x <= y <= z

…

>>> is_between (1, 3, 9)

True

>>> is_between (3, 7, 4)

False

>>>

**6.5 More recursion**

Here is an exiting announcement from the author, Allen B. Downey:

We have only covered a small subset of Python, but you might be interested to know that this subset is a complete programming language, which means that anything that can be computed can be expressed in this language. Any program ever written could be rewritten using only the language features you have learned so far (actually, you would need a few commands to control devices like the keyboard, mouse, disks, etc., but that’s all).

The statement above was proven by Alan Turing. The author of the book (Think Python), Professor Downey recommends to read Michael Sipser’s book *Introduction to the Theory of Computation* to learn more about this computer science pioneer.

Who is Alan Turing?

Alan Mathison Turing (23 June 1912 – 7 June 1954) was a British mathematician, logician, cryptanalyst and computer scientist. He was influential in the development of computer science, giving a formalisation of the concepts of “algorithm” and “computation” with the Turing machine, which can be considered a model of a general purpose computer. Turing is widely considered to be the father of the theoretical computer science and artificial intelligence.

Source: http://en.wikipedia.org/wiki/Alan_Turing

Moreover, the concepts learned that we have learned so far can be gauged with a few recursively defined mathematical functions.

A recursive definition is similar to a circular definition, in the sense that the definition contains a reference to the thing being defined. A truly circular definition is not very useful.

At this point, we are ready to apply the concepts we have learned so far to recursively mathematical functions.

A recursive definition is similar to a circular definition, in the sense that the definition contains a reference to the thing being defined. A truly circular definition is not very useful.

Professor Downey mentioned the word **vorpal**. I looked for the definition in Wikipedia just to realized that I was even more puzzled after I read it. Let us just stick to the definition provided by Professor Downey.

vorpal: An adjective used to described something that is vorpal.

**Factorial function**

0! = 1*n*! = *n* (*n* – 1)!

For instance:

If you can write a recursive definition of something, you can usually write a Python program to evaluate it.

Let us recall Polya’s first step to problem solving (or if we extrapolate, the first step into writing a programing function):

- Step 1) Understand the problem (or the function you wish to write).
- Understand how a
*factorial*function works.

- Decide what the parameters should be: A
*factorial*takes an integer. - Decide how the result should look like: If the argument happens to be 0, the our function must return 1.

- Understand how a

- Step 2) Make a plan
- The factorial function looks very similar to the
*countdown*function that we wrote in Chapter 5, section 8. We might just go back in order to find some inspiration for our plan.

- The factorial function looks very similar to the

- Step 3) Carry out the plan

>>> def factorial (n):

… if n == 0:

… return 1

… else: # Otherwise, execute a recursive call to find the factorial of n – 1 and then multiply by n.

… recurse = factorial (n-1)

… result = n * recurse

… return result

…

>>> factorial (3)

6

>>>

- Step 4) Look back at your work. How can it be better?

**6.6 Leap of faith**

Trust in the code blocks you created and tested.

Here is another example of a leap of faith!

**6.7 One more example**

Another example of a recursively defined mathematical function is the *fibonacci sequence of numbers* :

In the Fibonacci sequence of numbers, each number is the sum of the previous two numbers. Fibonacci began the sequence […] with 1,1, 2, etc. […]

1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377

Source: Wikipedia / Fibonnacci

- fibonnaci (0) = 0
- fibonnaci (1) = 1
- fibonnaci (
*n*) = fibonnaci (*n*– 1) + fibonnaci (*n*– 2)

If you try to follow the flow of execution here, even for fairly small values of n, your head explodes. But according to the leap of faith, if you assume that the two recursive calls work correctly, then it is clear that you get the right result by adding them together.

**6.8 Checking types**

The built-in function *isinstance* is introduced in this section. The function verifies the type of argument.

On section 6.5, we developed a function called *factorial*. Let us take another step further and check the type of the argument and make sure it is positive.

>>> factorial (‘banana’)

Factorial is only defined for integers.

>>> factorial (3.5)

Factorial is only defined for integers.

>>> factorial (-1)

Factorial is not defined for negative integers.

>>> factorial (8)

40320

>>>

This program demonstrates a pattern sometimes called a

guardian. The first two conditionals act as guardians [(not isinstance) and (elif n < 0)] , protecting the code that follows from values that might cause an error.The guardians make it possible to prove the correctness of the code.

**6.9 Debugging**

Playing Lego with coding allows us to work on very small pieces of code. This makes debugging sessions less burdensome as it provides “natural checkpoints” for debugging.

If a function is not working, Professor Downey considers three possibilities:

- Arguments: Verify that the function is getting the correct arguments.

A precondition is violated.- “To rule out the first possibility [Arguments], you can add a
*print*statement at the beginning of the function and display the values of the parameters (and maybe their types)”. - We can also write code to verify the preconditions explicitly: “Add a
*print*statement before each*return*statement that displays the return value”.

- “To rule out the first possibility [Arguments], you can add a

- Function: Verify that the function is syntactically correct. A postcondition is violated.
- The Picking Number strategy to verify code blocks can be an option to check the function’s results.
- “If the function seems to be working, look at the function call to make sure the return value is being used correctly (or used at all!)”

- Return value: Verify that the return value is what you expect (type and form) or how the return value is being used.
- Trace the flow of execution by adding
*print*statements. - Temporary variables often render debugging easier easier.

- Trace the flow of execution by adding

***

### 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

Hey there! Enjoyed Your write-up, doing the chapter myself right now. Are You still into programming or has the python loosened its grip?

Cheers and thanks for Your work!

PS. Not sure if my comment got through so I just left it here again.

Hi Tom,

Thanks for your comment.

I am still enjoying Python very much. I finished a Python class with Coursera earlier this year: https://www.coursera.org/specializations/python

Professor Severance has done an amazing job at really transmitting the Python basics.

Hey there! Enjoyed Your write-up, doing the chapter myself right now. Are You still into programming or has the python loosened its grip?

Cheers and thanks for Your work!

Pingback: Chapter 7: Iteration – Think Python | Python Project