Why Functions?
It may not be clear why it is worth the trouble to divide a program into functions. There are several reasons:
- Creating a new function gives you an opportunity to name a group of statements, which makes your program easier to read, understand, and debug.
- Functions can make a program smaller by eliminating repetitive code. Later, if you make a change, you only have to make it in one place.
- Dividing a long program into functions allows you to debug the parts one at a time and then assemble them into a working whole.
- Well-designed functions are often useful for many programs. Once you write and debug one, you can reuse it.
Throughout the rest of this course, often we will use a function definition to explain a concept. Part of the skill of creating and using functions is to have a function properly capture an idea such as “find the smallest value in a list of values”.
Variable Scope
When you declare variables inside a function definition, they are not related in any way to other variables with the same names used outside the function - i.e. variable names are local to the function.
| Code | Output |
|---|---|
my_name = "Fred" |
George |
In the above example, we have a variable called my_name which is
outside of the function print_name(). There is also a
variable called my_name inside of print_name().
These are two different variables. We can see this when we run the last
two lines:
| Code | Output | Notes |
|---|---|---|
print_name() |
George |
This displays the variable inside of the function, which is
assigned to the string |
print(my_name) |
Fred |
This displays the variable outside of the function, which is assigned
to the string |
This is called the variable scope. The scope of all
variables is the block they are declared in - starting from the point of
definition of the name. The scope of my_name that is outside of the
function (let's call it the "outside my_name") is the main body of
the program. The scope of the my_name variable that is
inside of the function (let's call it the "inside my_name") is the
function print_name(). The inside my_name is
considered to be local to the print_name()function. Here's
another example:
Example: Local Variable
x = 50
def
func(x):
print('x is',
x)
x = 2
print('Changed
local x to', x)
func(x)
print('x is still', x)
Output:
x is 50
Changed local x to 2
x is still 50
How It Works
The first time that we print the value of the name x with the
first line in the function's body, Python uses the value of the parameter
declared in the main block, above the function definition.
Next, we assign the value 2 to x. The name
x is local to our function. So, when we change the value
of x in the function, the x defined in the main block
remains unaffected.
With the last print statement, we display the value of
x as defined in the main block, thereby confirming that it is
actually unaffected by the local assignment within the previously called
function.
The global Statement
If you want to assign a value to a name defined at the top level of the
program (i.e. not inside any kind of scope such as functions or classes), then
you have to tell Python that the name is not local, but it is
global. We do this using the global
statement. It is impossible to assign a value to a variable defined outside a
function without the global statement.
Example: Global Statement
x = 50
def
func():
global x
print('x
is', x)
x =
2
print('Changed global x to',
x)
func()
print('Value of x is', x)
Output:
x is 50
Changed global x to 2
Value of x is 2
How It Works
The global statement is used to declare that x is a
global variable - hence, when we assign a value to x inside the
function, that change is reflected when we use the value of x in
the main block.
You can specify more than one global variable using the same global
statement e.g. global x, y, z.
Global Constants
You can use the values of such variables defined outside the function
(assuming there is no variable with the same name within the function).
However, this is not encouraged and should be avoided since it becomes unclear
to the reader of the program as to where that variable's definition is. Using
the global statement makes it amply clear that the variable is
defined in an outermost block.
That being said, having a global variable can cause a lot of confusion if its value is changed by multiple functions. In general, it is better to pass variables into functions as arguments, rather than share a global variable across an entire program.
However if the value assigned to the global variable does not ever change, it is called a global constant and its use is less likely to cause problems. In Python, there is no technical difference between a global variable which changes its value and a global constant which maintains its value – you declare and use them the same way. To avoid confusion, convention dictates that global constants are named in all capital letters, while global variables follow whatever naming convention you like.
# Global Constant Example
# The name of the game will never
change
# This is okay to use because it never changes
GAME_NAME = "League
of Leg Ends"
# Global Variable Example
# The score will constantly
change and by more than one function
# this could get confusing and would be
better to pass as an
# argument
score = 0
def
win_round():
score++
print("You won the round!")
print("Your score in",
GAME_NAME, "is now", score)
def lose_round():
score--
print("You lost the
round!")
print("Your score in", GAME_NAME, "is
now", score) Default Argument Values
For some functions, you may want to make some parameters optional and use default values in case the user does not want to provide values for them. This is done with the help of default argument values. You can specify default argument values for parameters by appending to the parameter name in the function definition the assignment operator (=) followed by the default value.
Note that the default argument value should be a constant. More precisely, the default argument value should be immutable - this is explained in detail in later lessons. For now, just remember this.
Example: Default Argument
def say(message,
times=1):
print(message *
times)
say('Hello')
say('World', 5)
Output:
Hello
WorldWorldWorldWorldWorld
How It Works
The function named say is used to print a string as many times
as specified. If we don't supply a value, then by default, the string is
printed just once. We achieve this by specifying a default argument value of 1
to the parameter times.
In the first usage of say, we supply only the string and it prints the string once. In the second usage of say, we supply both the string and an argument 5 stating that we want to say the string message 5 times.
CAUTION: Only those parameters which are at the end of the parameter list can be given default argument values i.e. you cannot have a parameter with a default argument value preceding a parameter without a default argument value in the function's parameter list.
This is because the values are assigned to the parameters by position. For
example, def func(a, b=5) is valid, but def func(a=5,
b) is not valid.
Keyword Arguments
If you have some functions with many parameters and you want to specify only some of them, then you can give values for such parameters by naming them - this is called keyword arguments - we use the name (keyword) instead of the position (which we have been using all along) to specify the arguments to the function.
There are two advantages - one, using the function is easier since we do not need to worry about the order of the arguments. Two, we can give values to only those parameters to which we want to, provided that the other parameters have default argument values.
Example: Keyword Arguments:
def func(a, b=5,
c=10):
print('a is', a, 'and b is', b, 'and c is',
c)
func(3, 7)
func(25, c=24)
func(c=50, a=100)
Output:
a is 3 and b is 7 and c is 10
a is 25 and b is 5 and c
is 24
a is 100 and b is 5 and c is 50
How It Works
The function named func has one parameter without a default
argument value, followed by two parameters with default argument values.
In the first usage, func(3, 7), the parameter a
gets the value 3, the parameter b gets the value 7 and
c gets the default value of 10.
In the second usage func(25, c=24), the variable a gets the
value of 25 due to the position of the argument. Then, the parameter
c gets the value of 24 due to naming i.e. keyword arguments. The
variable b gets the default value of 5.
In the third usage func(c=50, a=100), we use keyword arguments
for all specified values. Notice that we are specifying the value for parameter
c before that for a even though a is
defined before c in the function definition.
DocStrings
Python has a nifty feature called documentation strings, usually referred to by its shorter name docstrings. DocStrings are an important tool that you should make use of since it helps to document the program better and makes it easier to understand.
Basically, docstrings document the function so you can see what it does and any other information about it.
Amazingly, we can even get the docstring back from, say a function, when the program is actually running!
Example: DocStrings
def print_max(x,
y):
'''Prints the maximum of two
numbers.
The two values must be
integers.'''
# convert to integers, if
possible
x = int(x)
y =
int(y)
if x >
y:
print(x, 'is
maximum')
else:
print(y,
'is maximum')
print_max(3, 5)
print(print_max.__doc__)
Output:
5 is maximum
Prints the maximum of two numbers.
The
two values must be integers.
How It Works
A string on the first logical line of a function is the docstring for that function.
The convention followed for a docstring is a multi-line string where the first line starts with a capital letter and ends with a dot. Then the second line is blank followed by any detailed explanation starting from the third line. You are strongly advised to follow this convention for all your docstrings for all your non-trivial functions.
We can access the docstring of the print_max function using the
__doc__ (notice the double underscores) attribute (name belonging
to) of the function. Just remember that Python treats everything as an object
and this includes functions.
If you have used help() in Python, then you have already seen
the usage of docstrings! What it does is just fetch the __doc__
attribute of that function and displays it in a neat manner for you. You can
try it out on the function above - just include help(print_max) in
your program. Remember to press the q key to exit help.
Automated tools can retrieve the documentation from your program in this manner, which makes it really simple to write up documentation for your application. Therefore, I strongly recommend that you use docstrings for any non-trivial function that you write.
