Sometimes we have a specific task we would like our program to execute in multiple different places in the code. We could rewrite the task each time, but this could be tedious and make our code difficult to read, especially if the task is complicated. Instead, we can make use of functions, a separate space where we can write the instructions to this task and then when we want it to execute, we can simply call the function with one line of code.
We have already seen one function multiple times throughout these tutorials: print. Print performs the same task each time we call it - it outputs the message or variable that we pass to it. These messages or variables, what goes inside the parentheses when we call print, are called arguments, and they allow our functions to perform fundamentally the same task each time, but with different inputs so that the functionality is customizable. Here is an example of a simple function, which will print out the number we pass to it, plus 5:
def my_func(x):
print(x + 5)
my_func(0)
my_func(3)
my_func(10)
>>5
8
15
First, the syntax. We start with what’s called the function declaration with the keyword def. This keyword tells Python that we will now start defining a function. The word after def is the function name. After the name there is a set of parentheses, this is where the function’s parameters are defined. Parameters are placeholders for the arguments that will be entered at the time of calling the function. When the function is called, the parameter x is given the value of whatever argument is passed, and from there the rest of the function is called. In addition, for basic functions, an argument must be passed for each parameter specified in the function declaration. You should specify parameters for whatever variables in your function are not fixed and are dependent on the input to that function. Unlike other languages, the types of a Python function’s parameters do not need to be specified in the function declaration. In fact, the type of the passed arguments can change between function calls! You just need to make sure the operations which make use of that parameter can accept the data types it might be.
You can specify more than one parameter, separated by commas, such as in this example:
def my_func(x, y, z):
print(x+5, y+2, z+3)
my_func(0, 1, 2)
>>5 3 5
Note that if there are three parameters specified in the function definition, there must be three arguments passed to the function each time it is called, or else Python will return an error.
After the colon, we can implement the contents of the function starting on the next line, known as the function definition. Note the use of whitespace for indentation, which will tell Python that anything indented with that amount of whitespace under the function declaration is part of the function’s contents.
Something else to note is that although we defined the function above the lines where we called it, Python did not execute the function at the time it read it. Normally in a Python file, code will be executed top to bottom, but if you define a function, or as we will see later, a class, Python will pass over it and not perform the actions inside that function until the function is called. This is why the use of whitespace is key. Python interprets any line with no whitespace before it as ready to be executed, but it will know code inside a function definition should not be executed at this time, because of the def keyword and its whitespace.
An especially useful tool of the function is the return statement. When our code’s execution reaches a return statement, it immediately exits the function and now the function is the value of the variable specified after return. That was a lot, so here’s an example:
def my_func(x):
y = (x + 5) * 2
return y
new_val = my_func(12)
print(new_val)
>>34
In this example, our function takes a value, x, as input, and outputs a value equal to x plus five times two. A function with a return statement more closely resembles a mathematical function, where there is a number of inputs and the function outputs a value, after performing some permutations to the inputs. The value of the output is effectively assigned to the function call (my_func(12)). You can think of this syntax as the same thing as my_func(12) = (12 + 5) * 2.
To make effective use of our function’s output, we must assign that output to a variable (new_val in this example). If we do not assign it to some variable, the function call will still work, but we will lose the output forever.
I mentioned that the function call is effectively a variable that holds the output value. If that is the case, why do we need to assign it to another variable? Well, if you simply want to print the output, then you don't need to, you could just write print(my_func(12)). But, suppose you want to use the output of the function for some other calculations. We tend not to use the function call in other expressions further down the line, because each time we call the function, we run all the code within that function again. It is much more time and memory efficient to assign the output of a function to a variable, and then use that variable every time we want to use the output in some calculation.
Perhaps one of Python’s most useful capabilities is its ability to return multiple variables after a function, as opposed to other languages which only allow you to return one variable. We can do this by separating the variable names with a comma, like this:
def my_func(x, y):
x = x / 10
y = y * 10
return x, y
a, b = my_func(3, 5)
print(a, b)
>>0.3, 50
Notice how we assign the returned values to two variables, also separated by a comma. A function of this type, with multiple return values, will actually return what is called a tuple, a type of array in Python which we will go over later, and we can “unpack” this tuple by assigning two variables to the output at once, like above.
Inside functions we can use any sort of the structures we previously used. If-else branches, loops, and even other function calls are used inside functions all the time, like in this example:
def my_func(x, y, size):
for i in range(size):
x = x + y
return x
a = 5
b = -4
num_iters = 3
a = my_func(a, b, num_iters)
b = my_func(b, a, num_iters)
print(a)
print(b)
>>-7
-25
See if you can write down the calculations that the above program performs. Do you understand why it outputs those numbers?
Lastly, an important aspect of functions are its scope. Up until this point, every variable that we have created has been in the global scope. This means that we can access that variable anywhere in the program, and its value will be consistent based on what operations have been performed on it up until that point. However, a variable created within a function or as a parameter in the function declaration will be in the function’s local scope. These variables in the local scope only exist inside the function, and if we were to try to access them outside the function we would get an error. This is a reason why it is so important to return the variables whose values were altered inside the function and we want to save, because otherwise we could not access those values once the function call has ended. Observe this example and notice how the changes we make to the variable x do not stick after the function is called:
def my_func(x):
x = x + 7
x = 0
my_func(x)
print(x)
>>0
This happens because the variable created in the function, my_func, named “x”, is not the same variable as that declared in the global scope. If we do not return the value of x in the function, and then assign it to our global x, the function does nothing. Here is what it would look like if implemented correctly:
def my_func(x):
x = x + 7
return x
x = 0
x = my_func(x)
print(x)
>>7
For this reason, we recommend using variables inside your functions that do not have the same name as those in your global scope, to avoid confusion.
Variable scopes are confusing, and if you would like to do some more reading, here is a helpful link:
Coding with functions is a common practice in all applications of programming, and so I recommend practicing it until you are comfortable. Thanks for reading!
Challenge Activities:
Create a function which takes in three integers, and returns the largest of the three.
Create a function which takes in four floats, doubles each of them, and then returns each of their new values. Outside the function, print all the returned values separately.
Komentarze