Using Built-in Functions
Recall that a subroutine is a named helper algorithm that consists of a sequence of statements that performs a computation. In Python, subroutines are called functions, borrowing notation and nomenclature from mathematics. When you define a function, you specify the name and the sequence of statements. Later, you can “call” the function by name.
Function Calls
We have already seen several examples of function calls such as the type
function:
>>> type(42)
<class 'int'>
The name of the function is type
. The expression in parentheses is called the argument of the function. The result, for this function, is the type of the argument.
It is common to say that a function “takes” an argument and “returns” a result. The result is also called the return value.
Python provides functions that convert values from one type to another. The int
function takes any value and converts it to an integer, if it can, or complains otherwise:
>>> int('32')
32
>>> int('Hello')
ValueError: invalid literal for int(): Hello
int
can convert floating-point values to integers, but it doesn’t round off; it chops off the fraction part:
>>> int(3.99999)
3
>>> int(-2.3)
-2
float
converts integers and strings to floating-point numbers:
>>> float(32)
32.0
>>> float('3.14159')
3.14159
Finally, str
converts its argument to a string:
>>> str(32)
'32'
>>> str(3.14159)
'3.14159'
Math Functions
Python has a math module that provides most of the familiar mathematical functions. A module is a file that contains a collection of related functions.
Before we can use the functions in a module, we have to import it with an import statement:
>>> import math
This statement creates a module object named math
. If you display the module object, you get some information about it:
>>> math
<module 'math' (built-in)>
The module object contains the functions and variables defined in the module. To access one of the functions, you have to specify the name of the module and the name of the function, separated by a dot (also known as a period). This format is called dot notation.
>>> ratio = signal_power / noise_power
>>> decibels = 10 * math.log10(ratio)
>>> radians = 0.7
>>> height = math.sin(radians)
The first example uses math.log10
to compute a signal-to-noise ratio in decibels (assuming that signal_power and noise_power are defined). The math
module also provides log
, which computes logarithms base e
.
The second example finds the sine of radians
. The variable name radians
is a hint that sin
and the other trigonometric functions (cos
, tan
, etc.) take arguments in radians. To convert from degrees to radians, divide by 180 and multiply by π:
>>> degrees = 45
>>> radians = degrees / 180.0 * math.pi
>>> math.sin(radians)
0.707106781187
The expression math.pi
gets the variable pi
from the math module. Its value is a floating-point approximation of π, accurate to about 15 digits.
If you know trigonometry, you can check the previous result by comparing it to the square root of two divided by two:
>>> math.sqrt(2) / 2.0
0.707106781187
Composition
So far, we have looked at the elements of a program—variables, expressions, and statements—in isolation, without talking about how to combine them.
One of the most useful features of programming languages is their ability to take small building blocks and compose them. For example, the argument of a function can be any kind of expression, including arithmetic operators:
x = math.sin(degrees / 360.0 * 2 * math.pi)
And even function calls:
x = math.exp(math.log(x+1))
Almost anywhere you can put a value, you can put an arbitrary expression, with one exception: the left side of an assignment statement has to be a variable name. Any other expression on the left side is a syntax error (we will see exceptions to this rule later).
>>> minutes = hours * 60 # right
>>> hours * 60 = minutes # wrong!
SyntaxError: can't assign to operator
Fruitful Functions and Void Functions
Some of the functions we have used, such as the math functions, return results; for lack of a better name, we call them fruitful functions. Other functions, like print
, perform an action but don’t return a value. They are called void functions.
When you call a fruitful function, you almost always want to do something with the result; for example, you might assign it to a variable or use it as part of an expression:
x = math.cos(radians)
golden = (math.sqrt(5) + 1) / 2
When you call a function in interactive mode, Python displays the result:
>>> math.sqrt(5)
2.2360679774997898
But in a script, if you call a fruitful function all by itself, the return value is lost forever!
math.sqrt(5)
This script computes the square root of 5, but since it doesn’t store or display the result, it is not very useful.
Void functions might display something on the screen or have some other effect, but they don’t have a return value. If you assign the result to a variable, you get a special value called None
.
>>> result = print('Bing')
Bing
>>> print(result)
None
The value None
is not the same as the string 'None'
. It is a special value that has its own type:
>>> type(None)
<class 'NoneType'>
The functions we have written so far are all void. We will start writing fruitful functions in a few chapters.
The input
function
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.
>>> text = input()
What are you waiting for?
>>> text
'What are you waiting for?'
Before getting input from the user, it is 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 expect the user to type an integer, you can try to convert the return value to int
:
>>> prompt = 'What is your favorite number?\n'
>>> num = input(prompt)
What is your favorite number?
42
>>> int(num)
42
But if the user types something other than a string of digits, you get an error:
>>> num = input(prompt)
What is your favorite number?
I need to think about that
>>> int(num)
ValueError: invalid literal for int() with base 10
We will see how to handle this kind of error later.
Floor Division and Modulus
The floor division operator, //
, divides two numbers and rounds down to an integer. For example, suppose the run time of a movie is 105 minutes. You might want to know how long that is in hours. Conventional division returns a floating-point number:
>>> minutes = 105
>>> minutes / 60
1.75
But we don’t normally write hours with decimal points. Floor division returns the integer number of hours, rounding down:
>>> minutes = 105
>>> hours = minutes // 60
>>> hours
1
To get the remainder, you could subtract off one hour in minutes:
>>> remainder = minutes - hours * 60
>>> remainder
45
An alternative is to use the modulus operator, %
, which divides two numbers and returns the remainder.
>>> remainder = minutes % 60
>>> remainder
45
The modulus operator is more useful than it seems. For example, you can check whether one number is divisible by another—if x % y
is zero, then x
is divisible by y
.
Also, you can extract the right-most digit or digits from a number. For example, x % 10
yields the right-most digit of x
(in base 10). Similarly x % 100
yields the last two digits.
Debugging
One of the most important skills you will acquire is debugging. Although it can be frustrating, debugging is one of the most intellectually rich, challenging, and interesting parts of programming.
In some ways debugging is like detective work. You are confronted with clues and you have to infer the processes and events that led to the results you see.
Debugging is also like an experimental science. Once you have an idea about what is going wrong, you modify your program and try again. If your hypothesis was correct, you can predict the result of the modification, and you take a step closer to a working program. If your hypothesis was wrong, you have to come up with a new one. As Sherlock Holmes pointed out:
When you have eliminated the impossible, whatever remains, however improbable, must be the truth.
A. Conan Doyle, The Sign of Four
For some people, programming and debugging are the same thing. That is, programming is the process of gradually debugging a program until it does what you want. The idea is that you should start with a working program and make small modifications, debugging them as you go.
For example, Linux is an operating system that contains millions of lines of code, but it started out as a simple program Linus Torvalds used to explore the Intel 80386 chip. According to Larry Greenfield:
One of Linus’s earlier projects was a program that would switch between printing AAAA and BBBB. This later evolved to Linux.
The Linux Users’ Guide Beta Version 1
Glossary
- function
- A named sequence of statements that performs some useful operation. Functions may or may not take arguments and may or may not produce a result.
- function call
- A statement that runs a function. It consists of the function name followed by an argument list in parentheses.
- return value
- The result of a function. If a function call is used as an expression, the return value is the value of the expression.
- fruitful function
- A function that returns a value.
- void function
- A function that always returns
None
. - None
- A special value returned by void functions.
- module
- A file that contains a collection of related functions and other definitions.
- import statement
- A statement that reads a module file and creates a module object.
- module object
- A value created by an import statement that provides access to the values defined in a module.
- dot notation
- The syntax for calling a function in another module by specifying the module name followed by a dot (period) and the function name.
- composition
- Using an expression as part of a larger expression, or a statement as part of a larger statement.
- floor division
- An operator, denoted
//
, that divides two numbers and rounds down (toward negative infinity) to an integer. - modulus operator
- An operator, denoted with a percent sign (
%
), that works on integers and returns the remainder when one number is divided by another.
Self Checks
Check 1
Recall that if we have two points $p_1 = (x_1, y_1)$ and $p_2=(x_2,y_2)$, we can compute the Euclidean distance between them using the following formula:
\[d = \sqrt{(x_1-x_2)^2 + (y_1-y_2)^2}\]Finish the following Python program that computes the distance between two points.
import math
print("This program computes the distance between points")
x1 = float(input("Enter the x-coordinate of the first point: "))
y1 = float(input("Enter the y-coordinate of the first point: "))
x2 = float(input("Enter the x-coordinate of the second point: "))
y2 = float(input("Enter the y-coordinate of the second point: "))
dist = # TODO: convert the formula to Python here
print("The distance between the two points is", dist)
Check 2
- What is the difference between a “fruitful” function and a “void” function?
- Identify one example of a fruitful function and one example of a void function.
Acknowledgment:
This reading was originally written by Allen Downey in his open source book Think Python 2e. Downey's book is licensed under the GNU Free Documentation License, which allows users to copy, modify, and distribute the book.
This reading was modified by Titus H. Klinge in 2021 and presented above under the same license in order to better serve the students of this course.