If you are confused about user-defined functions? Your confusion ends today…
A user-defined function is a reusable block of code that you (the programmer) create from scratch in order to perform a specific task of your choice one or more times.
Unlike built-in functions which are included with the Python programming language fresh-out-of-the-box, a user-defined function allows you the functionality of creating your own fully customized tool; tailored to solve one specific problem.
The core advantage of using a user-defined function in your source code is flexibility. It gives you the power to perform a given task repetitively, without having to rewrite your entire program line by line.
In this tutorial I will be teaching you about user-defined functions and their syntax:
- the def keyword
- defining a function body
- parameters and arguments
- default parameters
- asserting preconditions
- short-circuiting functions with the return keyword
- defining docstrings
- *args (arguments)
- **kwargs (keyword-arguments),
- scope (Global and Local)
- calling your functions
Table of Contents
- Structure of User-Defined Functions in Python
- How To Call a Function in Python
- Parameters vs. Arguments
- Documentation (Docstrings)
- The Return Statement
- Asserting Preconditions
- Local Scope and Global Scope
- Real-world Example of Why User-Defined Functions Are Important
- Conclusion
Structure of User-Defined Functions in Python
Functions in Python follow a specific syntax with little variation. This syntax must be followed, otherwise, you will receive an error message from the Python console.
In the code block below you’ll find the standard syntax of a Python user-defined function.
def function_name(parameters):
"""docstring"""
statement(s)
return
Defining a function requires using the built-in Python keyword def, which tells the Python Interpreter that you are going to define a function body.
The def keyword needs to be followed by the name of the function.
Typically, when I am naming a function, I follow the common practice of naming my function based on the action that will be performed by the function. By convention, I write the name of my functions according to a standard pattern called “snake-case” (example: function_name).
Function Name (in Snake Case format) | Action (Task the function accomplishes.) |
upper_case | Converts all alphabetical characters in a string to upper case. |
lower_case | Converts all alphabetical characters in a string to lower case. |
times_two | Multiplies any integer by two. |
The parameters inside the parenthesis will be passing some values into this function. Parameters are optional; we will dive into deeper details on this subject later in this tutorial.
After the parenthesis, you must type a colon at the end of the function header to tell the Python Interpreter that this is the end of the first line of our function.
Next, we must consider our Docstring; this is the documentation that explains what this function does inside your function-body, and exactly how to use the function properly, this is optional but should be utilized if other programmers will be reading or even editing your code.
Your function should also include at least one valid statement that makes the function useful, for instance; printing something to the Python Console or performing an advanced calculation.
Lastly, the return statement will return the end value of the function; mainly an evaluated expression.
After performing a specific action of your choosing, this returned value can be stored in a variable by assigning your function to a variable while it is being called, we will also explore this topic later as well, but first, let’s take a look at the simple function below.
def greeting(name):
"""
This is a simple function
to pass your name and greeting you
"""
print("Hello " + name)
=> Join the Waitlist for Early Access.
How To Call a Function in Python
The code above is a simple example of creating your own function that greets a user, then prints that greeting to the Python Console where it can be read by the user.
The code block below shows how to call our user-defined “greeting” function. Notice how our function does not need an underscore in its name because it is only named with one word (greeting), though it remains in snake-case formatting.
greeting("Biden")
Output:
Hello Biden
Notice that we wrote “Biden” in the parenthesis of our function while calling the function.
The “Biden” string is referred to as an argument that was assigned to the “name” parameter that was defined in our function header. We will explore parameters and arguments now.
Parameters vs. Arguments
Most novice Python programmers don’t know the difference between parameters and arguments, so let’s distinguish what they both are…
Parameters: the arbitrary keyword(s) located in the parenthesis of a function definition, which acts as a place holder, similar to a variable, it stores values that can be accessed for data manipulations and calculations once the function is called.
Arguments: the value(s) passed to a function, then stored in parameters for the use of calculations, data manipulations, or other important tasks that support the purpose of a function within a program.
- positional arguments– an argument where the value stored in the parameter is assigned to that perameter based on the position of the argument in the parenthesis, and is not directly assigned to a perameter with an assignment operator “=”, like a variable assignement, ex. function(“Biden”).
- keyword arguments– an argument that is assigned to a paramerter directly with an assignment operator “=”, similar to variable assignment, ex. function(name=”Biden”).
def greeting(name):
"""
This is a simple function
to pass your name and greeting you
"""
print("Hello " + name)
greeting("Biden")
greeting(name="Biden")
Output:
Hello Biden Hello Biden
Default Arguments
Default arguments are keyword arguments that are assigned within a function definition rather than when a function is called.
Though, once the function is called a user has the opportunity to use the default argument assigned to the keyword parameter by calling the function without passing any new value to the keyword argument.
On the other hand, the user can overwrite the value stored in the keyword parameter by passing a new value to the keyword parameter while calling the function, preferably of the same data type as the default keyword argument to avoid encountering any errors in your program.
def hello(greeting="Hello"):
print(f"{greeting}, what is your name?")
hello(greeting='Hi there') # overwriting the default argument
Output
Hi there, what is your name?
Speaking of arguments let’s discuss two more kinds of arguments…
What Special Properties Do Arguments with * and ** prefixes have? (e.g. *args, **kwargs)
When creating a function we must make it able to receive values so it can be used multiple times inside your script(s), but what if you are uncertain about the number of arguments that you will need to be passed to your function?
Let’s see a small example:
def update(var):
for item in var:
print(item)
update([1, 2, 3], ["a", "b", "c"])
Output:
Traceback (most recent call last): File "main.py", line 5, in <module> update([1, 2, 3], ["a", "b", "c"]) TypeError: update() takes 1 positional argument but 2 were given
When running the code above you will get an error saying that “update() takes 1 positional argument but 2 were given”.
This happens because the Python interpreter expects to have only one argument (a list) and not multiple arguments (lists).
*args
Here comes the power of the *args parameter. Let’s edited the above code and see the new result:
def update(*var):
for item in var:
print(item)
update([1, 2, 3], ["a", "b", "c"])
Output:
[1, 2, 3] ['a', 'b', 'c']
Now the function is able to receive multiple lists and variables and use them without any error.
Another thing *args can perform is accessing a specific item inside a sequence:
def company(*boss):
print("The creator of Microsoft is " + boss[1])
company("Elon", "Gates", "Bezos")
Output:
The creator of Microsoft is Gates
The code can access any specific item inside the given tuple of objects. Yes, *args stores sequences of values in a tuple object.
Another thing I would like to mention before jumping into the use and benefits of **kwargs is that functions can also accept arguments with key=value syntax.
Let’s see an example:
def my_family(child3, child2, child1):
print("My youngest child is " + child2)
my_family(child1 = "Oliver", child2 = "Amelia", child3 = "George")
Output:
My youngest child is Amelia
**kwargs
Since we’ve created a function that can accept three parameters everything will work fine when calling the function with three arguments.
But, what if you don’t know how many arguments we need for our function?
Here comes the power of the **kwargs:
def my_son(**kid):
print("My son last name is " + kid["last_name"])
my_son(first_name = "Aiden", last_name = "Oliver")
Output:
My son last name is Oliver
The **kwargs makes your function able to accept multiple keywords without specifying the number of arguments.
Before we move ahead, let’s do a quick recap on parameters and arguments.
The keyword inside the parenthesis of a function definition is called a parameter. You can name this whatever you want, though it is best practice to make it descriptive of the type of data that will be passed to the function as an argument once the function is called.
Documentation (Docstrings)
To reiterate from earlier, a docstring is purely optional, but advised for user-defined functions, especially if you are working in teams with other programmers.
Directly below the function header is where you place your documentation; which is a short multi-lined string object enclosed in triple quotes explaining what this function does, and more specifically how to use it.
It’s very useful to access the documentation of a user-defined function inside the Python Console by printing your function’s name with the .__doc__ command/attribute, or passing your function’s name to the built-in help() function seen below:
def greeting(name):
"""
This is a simple function
to pass your name with a greeting.
"""
print("Hello " + name)
print(greeting.__doc__)
# or
help(greeting)
Output:
This is a simple function to pass your name with a greeting. Help on function greeting in module __main__: greeting(name) This is a simple function to pass your name with a greeting.
The Return Statement
So far we have only used print statements in our functions. Sometimes we may not want to print a value to the Python Console Instead, we may want to use a value calculated by a function for another calculation or purpose within our script. What do we do then?
Let’s see an example to understand more:
def calculation(num):
num * 2
calculation(4)
Output:
When you run the code you will get nothing on your screen.
This happens because we’ve performed the calculation but we didn’t tell the function to return any value(s) back to us. so let’s use the return statement this time around:
def calculation(num):
return num * 2
print(calculation(4))
Output:
8
Now you can see the function returns the number 8 which is obvious when multiplying 4 twice.
Notice that we still have to pass our calculation function to the print function when we call it in case we would like to see the returned value of 8 printed to the Python Console.
Our calculation function can also be saved to a variable while it is being called, then used like any other value, object, or expression that can be saved to a variable, seen below:
def calculation(num):
return num * 2
eight = calculation(4)
print(eight)
Output:
8
Note that nothing in a function definition can be executed beyond the return statement inside of a function. So in most cases, the return statement will be your final line in your function body.
The process of ending your function with a return keyword is known as shortcircuiting a function.
Asserting Preconditions
Assert is a keyword in Python used in a function or anywhere in your python code to flag an error if something does not logically happen you set before. Assert always assumes a specified condition evaluates to True.
Let’s see an example for this to understand more:
def my_age(age):
assert age > 0, "The age can not be negative"
print("My age is: ", age)
my_age(-1)
Output:
Traceback (most recent call last): File "main.py", line 5, in <module> my_age(-1) File "main.py", line 2, in my_age assert age > 0, "The age can not be negative" AssertionError: The age can not be negative
The above code obviously will show you an error, explaining “AssertionError: The age can not be negative”. The assert keyword will be useful inside your function because it lets the program know that there is something wrong with a particular piece of data.
Local Scope and Global Scope
Scope refers to the location of a variable within your Python code.
Global Scope: A global variable is a variable that is located/defined within your main Python script/file. A global variable can be accessed anywhere in your Python script, hint: global or accessible globally/non-exclusively across your program.
Local Scope: A local variable is a variable that is located/defined within a function body, that can only be accessed within the said function. The location of that local variable is within the local scope of the function because the variable is local /exclusive only to the function.
x = 5 # global x
def function():
x = 4 # local x
print(x)
function()
Output:
4
In our code block above we can see that the local x variable was printed instead of the global x variable because the print statement was executed on the local variable, not the global variable.
Real-world Example of Why User-Defined Functions Are Important
Quite often our programs model real-world situations, events, or problems, so let’s apply Python User-Defined Functions to a real-world problem in mathematics.
Exampe
Defining a user-defined function according to summation notation.
def function(first_value_of_n, last_valaue_of_n):
summation = 0
n = first_value_of_n
while n <= last_valaue_of_n:
formula = 3 * n
n += 1
summation = formula + summation
return summation
print(function(1, 100))
Output:
15150
Conclusion
When technological business problems nowadays force you to create very large and complicated software solutions; it becomes paramount to shrink your program into small bit-sized pieces of code with user-defined functions.
Thus making your program more readable, concise, and structured.
“The function of good software is to make the complex appear to be simple.”
-Grady Booch
Tanner Abraham
Data Scientist and Software Engineer with a focus on experimental projects in new budding technologies that incorporate machine learning and quantum computing into web applications.=> Join the Waitlist for Early Access.