You are on page 1of 16

What Is a Function?

def greeting():
"""This function prints a greeting"""
print("Hello!")

greeting()

OUTPUT:

Hello!

When defining a function, the first thing you need is the appropriate Python
keyword: def. This keyword tells the Python interpreter that what follows is a function.

def

The name of the function follows the def keyword. The name can be anything you'd
like, but you want to ensure that it makes sense. Above, the function name is greeting.
Function naming conventions and rules are similar to those for variable names.

def greeting

After the function's name, you'll find parentheses (). When you need to provide
information for the function, you'll find parameters inside of the parentheses.
Parameters will be discussed shortly, but the above function has none, so there's
nothing between each parenthesis.

def greeting()

Like for and while loops, as well as if and else, when defining a function the first line


must end with a colon :.

def greeting():

All of the Python code that will be executed when the function is used must be
indented, as you can see above. This is no different that an if block or for loop. The
indentation is maintained until the end of the function's definition.
The first line of code of the function is called a docstring (documentation string).
A docstring is used to specify the purpose of the function. A function's docstring is
defined by including a string literal as the first statement in the function's definition.
A string literal is text enclosed within triple-quotes, and they can be a single line or
multiple lines. Although it is not required, all functions should have a docstring.
def greeting():
"""This function prints a greeting"""

The final line of code of the greeting function is a call to the print()function to print out


the greeting. Other than the docstring, this represents the body of the function. The
body can contain as many operations as necessary, although the function below only
has one.

def greeting():
"""This function prints a greeting"""
print("Hello!")

greeting()

Below the function definition, you'll find the line of code that calls the
function: greeting(). When you define a function, like how greeting was defined above,
the code is not executed unless it is called, or invoked.

Providing Data to a Function


As you build functions, you'll find that in order for the function to perform its
operations, it may require data. In the previous example, the greeting function did not
require any data. However, below, you'll find a new function definition that does.

def increment(value):
"""This function increments a value"""
print("Old value =", value)
value += 1
print("New value =", value)

increment(10)

OUTPUT:

Old value = 10
New value = 11

Function Parameters
In the definition of the increment function above, you should see that there is now a
variable name nestled between the parenthesis:

def increment(value):

The value variable is called a parameter of the function. A function can have zero or


more parameters, and the sequence of the parameters is your choice (although it will
matter later).
Inside of the function's definition, these parameters can be used like any other
variable. However, if you change the value of the parameter, it will only remain
changed within the function's definition. You'll learn more about this shortly.
When a function has parameters, anytime that function is used, the parameters must
be provided. The last line of the above sample code shows how the function is
invoked and passed its required input.

increment(10)

If a value for the parameter is left out of the call to the function, it will produce an
error (NOTE: the # ... below means that the other code was left out in order to
highlight the relevant code; you will see this from time-to-time in this course):

# ...
increment()

OUTPUT:

Traceback (most recent call last):


File "/Users/username/Desktop/my_Python/lesson_5.py", line 7, in <module>
increment()
TypeError: increment() missing 1 required positional argument: 'value'

As you can see above, the error was verify specific as to the problem:
TypeError: increment() missing 1 required positional argument: 'value'
But, what is an argument?

Arguments to a Function
When a function requires input, its definition includes parameters, as you saw above.
When you make use of the function by calling/invoking it, you must provide the
required input. The data that you provide for each parameter is called an argument.
The increment function had one parameter value:
def increment(value):

In the call to increment, a single value 10 was provided: That is the argument.


Take a look at another example (there is no need to try this code yourself):

def my_function(how_many, of_what, it_tastes):


# do stuff

Above, the my_function definition includes three parameters: how_many, of_what,


and it_tastes. Below is the code that calls the above function:

my_function(10, 'apples', 'yummy')

The call to my_function includes three arguments — 10, 'apples', and 'yummy' — one for


each parameter. 10 is the argument corresponding to
the how_many parameter; 'apples' is the argument corresponding to
the of_what parameter; 'yummy' is the argument corresponding to
the it_tastes parameter.

Optional Function Parameters


Functions can have optional parameters. This is accomplished by providing a default
value for a parameter. To illustrate, take a look at the code below that modifies
the increment function to take a second parameter named: step_size. The call to the
function has also been modified to provide the required argument for the new
parameter.

def increment(value, step_size):


"""This function increments a value"""
print("Old value =", value)
value += step_size
print("New value =", value)

increment(10, 5)

OUTPUT:

Old value = 10
New value = 15
As you can see above, the step_size parameter is used as the amount to increment
the value of value. Previously, it was incremented by 1; in this case, you can
specifically set the step size (2 is used in the example).
To illustrate an optional parameter, the step_size parameter is given a default value
using the assignment operator = and the default value. Below, the default value of
the step_size parameter is 1.

def increment(value, step_size=1):


"""This function increments a value"""
print("Old value =", value)
value += step_size
print("New value =", value)

increment(10,5)
increment(10)

OUTPUT:

Old value = 10
New value = 15
Old value = 10
New value = 11

Now, there are two calls to the increment function:

increment(10,5)
increment(10)

The first call to increment includes arguments for both parameters. The output, as
expected, increments the value by 10 to 15.
The second call does not include the argument for the second parameter. Thus, the
function uses the default values that was specified in the function's definition. The
output shows that the value of 10 was incremented by the default step size (1) to 11.

Keyword Arguments
Above, you saw that you must provide arguments to a function in the same
sequence as expressed in the function's definition. Each of these arguments is
referred to as a positional argument.
However, arguments can also be provided as a key-value pair, which means the
order is no longer relevant. To illustrate take a look at the change to the call to
the increment function below:

increment(value=2, step_size=2)

value=2 and step_size=2 are each a keyword argument; the key and value are both
provided.
If the sequence is changed, it will still work and produce the same output:

increment(step_size=3, value=3)

As you can see, when you use keyword arguments, the sequence of the function's
parameters is irrelevant.

Returning Data From a Function


More often than not, the functions that you create in your apps will return a value or a
set of values. Consider the example you saw earlier with the increment function; it
incremented the value that was provided as an argument and printed it to the
console. Below, the function has been modified to, instead, return the result of the
arithmetic operation.

def increment(value, step_size=1):


"""This function increments a value"""
return value + step_size

new_value = increment(5, 3)
print("The new value is", new_value)

OUTPUT:

The new value is 8

In the definition of the increment function, take a look at the one line of code (not the
docstring):

return value + step_size

To return a value from a function, you use the return keyword followed by the value,
variable, or expression.
When increment is called, the value returned by the function is captured in
the new_value variable, which you can see as it's printed to the console.
Here's another example:

def sum(x, y):


"""This function sums the inputs"""
return x + y

result = sum(10, 15)


print("The sum of 10 and 15 is", result)

OUTPUT:

The sum of 10 and 15 is 25

This time, the sum function returns the sum of x and y. The result variable is assigned


this returned value, and it is added to the message printed to the console.
You can return any data type from a function. You can return a number, string, list,
dictionary, and tuple.
Take a look at the function below that returns a tuple of dictionaries:

def get_settings():
"""This function returns two dictionaries as a tuple"""
dict1 = {'name': 'Bob', 'color': 'blue'}
dict2 = {'name': 'Sally', 'color': 'red'}
return (dict1, dict2)

tuple = get_settings()
print(tuple)

OUTPUT:

({'name': 'Bob', 'color': 'blue'}, {'name': 'Sally', 'color': 'red'})

As you can see, you have a lot of flexibility when it comes to the types of data you
can return from your functions.

Returning "Nothing" From a Function


All functions actually return a value, whether you specify it or not. If there is no
explicit return statement, the function returns None, which is another Python keyword.
The None keyword is a special type in Python that represents nothingness. If a
variable has a value of None, it ultimately means it has no value.
Take a look at the code below. It contains the first function that you saw in this
lesson — greeting() — which does not return anything explicitly.

def greeting():
"""This function prints a greeting"""
print("Hello!")

print(greeting())

OUTPUT:

Hello!
None

As you can see in the output, when the "result" of the greeting() call is printed to the
console, it prints the value None. You can see this below the first line of the output,
where "Hello!" is printed.
Great! Now that you understand how to define a function with or without parameters,
invoke a function with or without parameters, and return data from a function, it's
time to discuss scope.

Local Variables and Scope


When declaring variables inside of a function, they are not related to any other
variable with the same name that is used outside of that function; this means the
variable names are considered local to that function. This is known as the scope of
the variable. All variables have the scope of the block that they are declared in,
starting from the definition of the function.
When talking about scope, all variables in a program may not be accessible in all
locations of that program. It all depends on where the variable was declared. The
scope of a variable determines where that variable can be accessed. The two basic
scopes of variables in Python are global and local.
What this means is that local variables can be accessed only inside the function in
which they are declared, whereas global variables can be accessed throughout the
program by all functions. When a function is called, the variables inside that function
are brought into scope.
TAKE AWAY: - Variables that are defined inside a function body have a local scope,
and those defined outside have a global scope.
Let's take a look at a few examples:
# this `user` variable is declared outside of the function
user = 'Andrew Jones'

def my_function(first, last):


# this `user` variable is declared inside of the function
# and is unrelated to the `user` variable declared outside of the function
user = first + ' ' + last
return user

print(user)

What do you think will be printed when the print function is executed?
OUTPUT:

Andrew Jones

The user variable that was declared outside of the function is printed. Now, if you
want to print the user variable in the function you would need to invoke the function
like so:

print(my_function('John', 'Smith')

OUTPUT:

John Smith

Here you can see that the function was invoked and the user variable inside of the
function is used to store the new name.
In the following example, the global variable user will be used inside of the function.

# The user variable is in global scope


user = "Andrew Jones"

def the_user():
"""Return the value of global variable user"""
# The global variable user is returned
return user

Now, when the function is invoked the value of the global variable user will be used.


print(the_user())

OUTPUT:

Andrew Jones

The Global Statement


As you saw earlier, variables defined outside of any function are global and can be
referenced from within a function. However, these values cannot be changed. If you
need to change a global variable, you need to declare it inside of the function's
definition using the global keyword.
For example,

y = 25

def my_function():
global y

print('y is', y)
y=5
print('the new value of global y is', y)

my_function()
print('y is now', y)

When this code snippet is executed the output is:


OUTPUT:

y is 25
the new value of global y is 5
y is now 5

Unnamed, Anonymous Functions


The functions that you've seen so far all have a name such that you can invoke them
elsewhere in code. You can also create functions that do not have a name — making
them, in a sense, anonymous —. Of course, you are probably wondering why you
would them.
In addition to showing you how to implement such unnamed functions, when and
why you would use them is discussed below. However, before you dive into them,
you will be installing a tool that helps with formatting.

Setup
In VS Code, ensure your integrated terminal is open. If not, you can press control +
~ to open it.
In the integrated terminal, enter the following command and hit enter (if yapf is
already installed, it will simply inform you):

pip3 install yapf

Next, open the User Settings of VS Code:

 Shortcut for MacOS is cmd ,


 Shortcut for Windows is ctrl ,

In the user settings, you will need to go to Extensions and then Python. Then scroll
down until you get to a section for Formatting: Yapf Path and add the word yapf to the
box below, as shown:
Once you have the settings configured, cmd + s or ctrl + s to save. You can close the
settings window once finished.

Lambda Functions
The lamda operator is used to create small, unnamed, anonymous functions.
These lambda function are considered throw-away functions, because they're only
used when they're defined. Most of the time, lambda functions are used in
combination with the built-in list functions filter() and map(). You'll learn about these
shortly.
When creating a lambda function, the following syntax is used:

lambda parameter-list: expression

Take a look at the example below which creates a lambda function and assigns it to
the variable my_lambda:

# create lambda function and assign to variable `my_lambda`


my_lambda = lambda x, y : x + y
# print the results of calling the lambda function
print(my_lambda(4, 5))

The result would be:


OUTPUT:

Here's another example:

a = lambda x: x > 10

print(a(20))

This function returns:


OUTPUT:

True

This new lambda function a tests whether the input x is greater than 10,
returning Trueif so and False if not. After passing in the argument of 20, the function
executes 20 > 10 and then returns the value of True (because 20 is greater than 10).

Operations That Can Be Performed


on Collections
map()
The map() function is used to perform an operation (or series of operations) on every
item that is contained within a collection (like a list or tuple), returning the results of
the operation as a list (sort of). This is best illustrated with an example.
Consider the following code which takes, as input, a list of numbers and then
squares each of them:

# 1. the list of numbers


numbers = [1, 2, 3, 4, 5]

# 2. the lambda function to square a number


square = lambda x: x * x
# 3. use `map` to apply the squaring lambda function to
# every item in the list of `numbers`
map_results = map(square, numbers)

# 4. `map` returns a special type of data, but it can be converted


# to a list using the `list` function
results = list(map_results)

# 5. print the results


print(results)

OUTPUT:

[1, 4, 9, 16, 25]

The above code has numbered comments that are discussed below:
1. First, a list of integers is created and assigned to the numbers variable.
2. A lambda function for squaring a number is created and assigned to the
variable square.
3. The map function is called. As you can see, the map function takes two
parameters:
o The lambda function to be applied to every item in a collection is the
first parameter.
o The collection of items to which the lambda function will be applied is
the second parameter.
The lambda function that was created in step 2 is the first argument, while
the numbers list that was created in step 1 is the second argument. In the next
code example, you'll see a situation where there are more than two
parameters.
The results of the call to map is stored in the variable map_results.
4. The value returned from the call to map is map object. If it were printed to the
console, it would look like the following:
5. <map object at 0x1022a0320>

However, this is not so useful, so it is converted into a list using list() and


stored in the variable results. You saw this in an earlier lesson when using
the range()function.
6. This prints out the results variable, which contains the conversion from
the mapresults to a list. As expected, this prints out a list, where each value is
the square of the corresponding value in the original number list.
Below is another example. This time, the lambda function is not stored in a variable;
instead, it is passed directly to the call to map. Also, there are two lists this time, so
the call to map includes both!

# declare two lists of integers


list_a = [1, 2, 3, 4, 5]
list_b = [11, 12, 13, 14, 15]

# call `map` with a lambda function that sums two numbers


# the first number comes from `list_a`, the second comes from `list_b`
map_results = map(lambda val_a, val_b: val_a + val_b, list_a, list_b)

# print results (converting map result to list within print statement)


print(list(map_results))

OUTPUT:

[12, 14, 16, 18, 20]

Above, the call to map includes the lambda function as the first argument, list_a as
the second argument, and list_b as the final argument. This is different from the
previous example, where map was only provided two arguments.

map_results = map(lambda val_a, val_b: val_a + val_b, list_a, list_b)

Filtering a Collection - filter()


The filter function is used to weed through a list of items, returning only those that
satisfy a condition. This condition takes the form of a lambda function that
returns True if the item is to be included, or False if it should be excluded.
The use of the filter function is the same as the map function. The first parameter is
the lambda function, while the second parameter is the collection.
Take a look at the example below, which filters out the odd numbers of the provided
list, returning only the even numbers:

# 1. the list of numbers


numbers = [1, 2, 3, 4, 5]

# 2. the lambda function to return True only if the value is even


is_even = lambda x: x % 2 == 0

# 3. call `filter` using the `is_even` lambda function and the list `numbers`
filter_results = filter(is_even, numbers)

# 4. `filter` returns a special type of data like `map`, but it can be converted
# to a list using the `list` function
results = list(filter_results)

# 5. print the results


print(results)

OUTPUT:

[2, 4]

Breaking down the above numbered comments:


1. Like in the map() example, numbers is a list of integers. This represents the
input collection that will be filtered.
2. This is the lambda function that will return True if the parameter is even,
otherwise False. For items to be included in the results of a call to filter(), it
must return True.
3. The filter function is called. Like the first map() example, you can see that it
takes two arguments: the lambda function and the collection. The results of
the call to filter is stored in the variable filter_results.
4. The value returned from the call to filter is a filter object, which is converted to
a list using the list() function like you saw above with map(). If it were printed to
the console, it would look like the following:
5. <filter object at 0x1041e3358>

6. This prints out the results variable, which contains the conversion from


the filterresults to a list. As expected, this prints out a list that contains only
even numbers.
Congratulations! You've now learned some very important and useful features of the
Python programming language. You will find functions everywhere, and in time, you'll
find how powerful lambdas can be, particularly when used in conjunction
with map() and filter(). There are, of course, many other applications where lambda
functions can be used.

You might also like