At this stage we have already unpacked a lot of functionality and are able to build complex programs. If you have started any project on the side, you probably noticed that you may end up repeating the same tasks hera and there in your code, and that this implies repeating several lines of code. This is unefficient for a number of reasons, mainly efficiency (you need to type more code) and maintainability (if you need to make any change in your code, you have to make the same change different times!)
Functions are a convenient way to divide your code into useful blocks, allowing us to order our code, make it more readable, reuse it, and save some time.
Functions also allow us to take a divide and conquer approach into coding (or divide and code ;)) pin which we define the business logic of our application from top to bottom, defining first the general logic and dividing the problem into smaller parts that are easier to manage.
Functions are defined with the keyword def and the code inside a function must be indented. The code inside a function is executed when you call the function, not when you define it.
[1]:
def first_function():
print("This is a function")
In order to call a function, just write the name of the function, followed by parenthesis. This type of statement is known as a function call statement:
[5]:
# Call the function
first_function()
This is a function
Arguments¶
Functions can receive arguments (or parameters) from the call statement to perform operations on them. The parameters are defined in the function clause, in the parameters that follow the function name, and may not be assigned any value until the function call.
For instance, look at the following examples:
[ ]:
def greetings(username):
print("Hello", username, "!")
greetings("John")
[1]:
def sum_two_numbers(a, b):
return a + b
addition = sum_two_numbers(5, 6)
print(addition)
11
Named arguments and default values¶
Named arguments are any parameters that have a name, such as those in the example above. Note that in the second example, we did not specified which values correspond to each summand a or b. Python assigned the provided values from left to right, but we could explicitly define the value of each summand by passing the name in the functional call statement like this:
[2]:
print(sum_two_numbers(a=6, b=5))
11
Named arguments can have a default value assigned in the definition of the parameter. We do not need to provide a value to these arguments to use the function, if not provided, the default value will be used:
[9]:
def my_power(a, b=2):
return b**a
print(my_power(a=3))
print(my_power(a=2, b=3))
8
9
☝ Warning! non-default (i.e. parameters without a default value) parameters must precede default parameters
Functions can use an arbitrary number of arguments packed in a tuple variable (see the Iterable Objects II tutorial for more on packing):
[4]:
# This function will print the summands and return the sum
def sum_numbers(*summands):
print("adding up numbers:")
print(summands) # Note that the summands are packed into a tuple
res = 0
for s in summands:
res += s
return res
# the built-in function sum adds the members of the iterable passed as an argument and is very similar to this function...
c = sum_numbers(1, 3, 4)
print("the sum is: ")
print(c)
d = sum_numbers(4,5,6,7)
adding up numbers:
(1, 3, 4)
the sum is:
8
adding up numbers:
(4, 5, 6, 7)
In the example above, the parameters do not have names, we can also pack named parameters into dictionaries:
[11]:
def my_power(a, b=2):
return b**a
dict_1 = {"a": 3}
print(my_power(**dict_1)) # Parameter a is packed into a dictionary, then unpacked and passed to the function
dict_2 = {"a":2, "b": 3}
print(my_power(**dict_2))
8
9
Variables Scope¶
It is important to note that the variables defined and assigned within a function are local, or have a local scope, which means that they cannot be accessed outside the function. Conversely, the variables that we define before the definition of the function are global, or have a global scope and can be accessed in the scope of the function.
[1]:
def sum_two_numbers(a,b):
c = a + b #c is defined and assigned inside the function as the sum of a and b
return c
print(sum_two_numbers(3,2)) # This works, because c is defined when the function is called
print(c) #This won´t work because c does not exist in this context, only in the context of the function
5
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-1-89928d6f07d6> in <module>
4
5 print(sum_two_numbers(3,2)) # This works, because c is defined when the function is called
----> 6 print(c) #This won´t work because c does not exist in this context, only in the context of the function
NameError: name 'c' is not defined
Can you write a function to reverse a given text? The function will accept the text as a parameter and will return the sentence in reverse order.
[1]:
# define "reverse" function and use it to reverse "sentence" variable
def reverse(my_string):
# insert your code in here
sentence = "No lemon, no melon"
print(reverse(sentence))
nolem on ,nomel oN