Prof. Dario Abbondanza
In the context of programming, a function is a named sequence of statements that performs a computation.
To define a function, you specify:
Later, you can “call” the function by name.
This is similar to what we said for values and variables.
... we have already seen many examples of function calls:
type(42)
int
The name of the function is type.
The expression in parentheses is called the argument of the function (aka input).
The result (aka output) of a function is also called the return value.
It is common to say that a function “takes” an argument and “returns” a result.
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
int('32')
32
... or complains otherwise
int('Hello')
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-3-3f8bc6d8fcab> in <module>() ----> 1 int('Hello') ValueError: invalid literal for int() with base 10: 'Hello'
int
can convert floating-point values and strings 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
str
converts its argument to a string:
str(32)
'32'
str(3.14159)
'3.14159'
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
... under the hood, this creates a module object named math.
If you display it, you get some information:
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 (aka period).
This format is called dot notation.
signal_power = 350; noise_power = 10
ratio = signal_power / noise_power
decibels = 10 * math.log10(ratio)
print(str(decibels) + " dB ")
radians = 0.7
height = math.sin(radians)
15.440680443502757 dB
here we used log10
to compute a signal-to-noise ratio in decibels
math
module also provides log
, which computes logarithms base
e
degrees = 45
radians = degrees / 180.0 * math.pi
math.sin(radians)
0.7071067811865475
here, the name of the variable is a hint that, as other trigonometric functions, it only takes arguments in radians!
The expression math.pi
gets the variable pi
from the math
module, or better: a floating-point approximation of its value!
If you know trigonometry, you can check the previous result by comparing it to half the square root of 2:
math.sqrt(2) / 2.0
0.7071067811865476
One of the most useful features of programming languages is their ability to compose small building blocks.
The argument of a function can be any kind of expression, including arithmetic operators:
x = math.sin(degrees / 360.0 * 2 * math.pi)
print(x)
0.7071067811865475
... even function calls:
x = math.exp(math.log(x+1))
print(x)
2.7071067811865475
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)
hours = 3
minutes = hours * 60 # right
hours * 60 = minutes # wrong!
File "<ipython-input-45-2be1c89a3aa6>", line 1 hours * 60 = minutes # wrong! ^ SyntaxError: can't assign to operator
We have only seen functions that come with Python, but it is also possible to add new functions.
Specifying:
def print_lyrics():
print("I'm a lumberjack, and I'm okay.")
print("I sleep all night and I work all day.")
def
is a keyword that indicates this is a function
definition.
print_lyrics
.The rules for function names are the same as for variable names.
... avoid having a variable and a function with the same name!
The header has to end with a colon and the body has to be indented.
By convention, indentation is always four spaces.
The body can contain any number of statements.
The strings in the print statements are enclosed in double quotes.
Single quotes and double quotes do the same thing, except when a single quote (an apostrophe) appears within the string, as above.
All quotation marks (single and double) must be straight quotes. “Curly quotes”, like the ones in this sentence, are not legal in Python.
Typing a function definition in interactive mode, the interpreter prints dots
(...
) to let you know the definition is uncomplete:
>>> def print_lyrics():
... print("I'm a lumberjack, and I'm okay.")
... print("I sleep all night and I work all day.")
...
To end the function, enter an empty line!
Defining a function creates a function object, which has type function:
print(print_lyrics)
<function print_lyrics at 0x7efc24806ae8>
type(print_lyrics)
function
Syntax for calling custom function is the same as for built-in:
print_lyrics()
I'm a lumberjack, and I'm okay. I sleep all night and I work all day.
Once you define a function, you can use it inside another function:
def repeat_lyrics():
print_lyrics()
print_lyrics()
repeat_lyrics()
I'm a lumberjack, and I'm okay. I sleep all night and I work all day. I'm a lumberjack, and I'm okay. I sleep all night and I work all day.
... the code fragments from the previous section, all together, looks like this:
def print_lyrics():
print("I'm a lumberjack, and I'm okay.")
print("I sleep all night and I work all day.")
def repeat_lyrics():
print_lyrics()
print_lyrics()
repeat_lyrics()
I'm a lumberjack, and I'm okay. I sleep all night and I work all day. I'm a lumberjack, and I'm okay. I sleep all night and I work all day.
This program contains: two function definitions and a function call
In other words: the function definition has to run before the function gets called!
To ensure that a function is defined before its first use, you have to know the order statements run in (aka flow of execution).
Function definitions do not alter the flow of execution of the program: remember that statements inside the function don’t run until the function is called!
A function call is like a detour in the flow of execution.
Instead of going to the next statement, the flow:
... simple enough, until you remember that one function can call another.
While in the middle of a function...
the program might have to call (and run the statements in) another function
... and there
it might have to run yet another function!
Thus, when you read a program, you don’t always want to read from top to bottom.
... it makes more sense to follow the flow of execution!
Some functions require an argument, some others take more than one argument:
math.sin
a numbermath.pow
the base and the exponentInside the function, the arguments are assigned to **local** variables called **parameters**.
def print_twice(bruce):
print(bruce)
print(bruce)
bruce
This function works with any value that can be printed.
print_twice('Spam')
Spam Spam
print_twice(42)
42 42
print_twice(math.pi)
3.141592653589793 3.141592653589793
Same rules of **composition** that apply to built-in functions apply to custom functions too.
print_twice(math.cos(math.pi))
-1.0 -1.0
Arguments are evaluated before the function is called. You can also pass a variable as argument.
michael = 'Eric, the half a bee.'
print_twice(michael)
Eric, the half a bee. Eric, the half a bee.
The name of the variable we pass as argument (michael
) has nothing to do with the name
of the parameter (bruce
).
It doesn’t matter what the value was called **back home** (in the caller); here in print_twice, **we call everybody bruce**.
When you create a variable inside a function, it is local, which means that it only exists inside the function.
def cat_twice(part1, part2):
cat = part1 + part2
print_twice(cat)
This function:
def cat_twice(part1, part2):
cat = part1 + part2
print_twice(cat)
line1 = 'Bing tiddle '
line2 = 'tiddle bang.'
cat_twice(line1, line2)
Bing tiddle tiddle bang. Bing tiddle tiddle bang.
When cat_twice
terminates, the variable cat
is destroyed.
Trying to print it, we get an exception:
print(cat)
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-71-7c3364e51d98> in <module>() ----> 1 print(cat) NameError: name 'cat' is not defined
Parameters are also local: outside print_twice
... nobody knows bruce
print(bruce)
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-72-f7a937b82c5b> in <module>() ----> 1 print(bruce) NameError: name 'bruce' is not defined
Some of the functions we have used, return results; other, perform an action but don’t return a value.
They are called void functions.
When your function returns a value, you usually want to do something with it:
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 function all by itself, the return value is lost forever!
math.sqrt(5)
Contrary, void functions might:
They don’t have a return value: if you assign the result to a variable, you get a special value called None.
result = print_twice('Bing')
print(result)
Bing Bing None
It is a special value that has its own type.
print(type(result))
<class 'NoneType'>
... why it is worth the trouble to divide a program into functions. There are several reasons:
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.
It 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.
It is also like an experimental science: