Python Functions – How To Define And Call A Python Function

This video tutorial explains Python Functions and their types like user define & built-in functions. You will learn to define and call a Python Function:

Though the creator of Python “Guido Van Rossum” didn’t intend Python to be a functional language, functions play a major role in Python.

We can define a Function as a box that encloses statements to be used and reused whenever the need arises. In this tutorial, we will discuss Python functions along with simple examples.

Python functions have certain properties that make them ideal for large and complex programs. Python has three types of functions – Built-in, User-defined and Anonymous functions.

=> Visit Here To Learn Python From Scratch

Python Functions Part A

Functions In Python: Video Tutorials

Function Arguments In Python: Video #1

Functions, Calling a Function & Return Statement in Python: Video #2

Why Use Python Functions

Functions are a great deal, even for other programming languages. Functions are important in Python at the point that we have built-in functions (functions pre-defined in Python).

Before we get into the details, let’s get an understanding of why functions are important:

  • Are first-class objects
  • Are Higher-order functions
  • Provide code reusability
  • Provide procedural decomposition

First-Class Objects

Functions in Python are first-class objects just as integers, strings, and dictionaries. Being a first-class object comes with the properties that enable programming with a functional style.

These properties:

  • Can be created at runtime.
  • Can be assigned to variables and used as elements in a data structure.
  • Can be passed as an argument to other functions.
  • Can be returned as a result of other functions.

Don’t be worried if the above properties are confusing. As we progress in this tutorial, we shall understand them better.

Higher-Order Functions

In Python, functions can take other functions as arguments and/or return as a result of a function. This makes life easy for some functions like map, filter which are some of the well-known higher-order functions.

Example 1: Using the map() function, compute a list of integers from a string of numbers.

The built-in map function will take in two arguments, a function (int) and our string of numbers. It will then pass each element of the string into its argument function to be computed. This wouldn’t have been possible if Python functions weren’t of higher-order.

# string of numbers
str_numb = "123456789" 
# create a list of integers from a string of numbers
result = list(map(int, str_numb)) 

print("RESULT: ", result)

Output

higher order functions

Code Reuse

As mentioned above, the functions enclose statements. This saves us from writing the same statement, again and again, each time when we need them and this usually leads to duplication of code.

If we have a logic that we’ll love to use in different areas of our code, then it will be wise and professional to package them in a function rather than repeating the logic in different areas.

The term used to describe this phenomenon is “reusability” and it follows a powerful principle in software development called Don’t Repeat Yourself (DRY)

Procedural Decomposition

In Python, functions help to split systems into pieces(modules), thereby making them easier to manage and maintain.

Functions enable us to implement a very powerful algorithm design paradigm called “Divide-and-Conquer” that basically breaks down an idea into two or more sub-ideas, and makes them simple enough to implement.

Imagine that we want to implement the process of us “leaving the house to work” every morning.

If you are someone who:

  • Gets up at 6 am,
  • Meditates on the word of God for 30 minutes,
  • Freshens up for 15 minutes,
  • Takes breakfast for 10 minutes,
  • Then finally walks to work.

Then you will realize a couple of sub-processes that govern the process of us “leaving the house to work”.

We had already broken down the process into sub-processes and implementing it will be easy as we can clearly isolate the sub-processes and implement them one at a time using functions.

Defining A Function

Earlier in this tutorial, we saw two built-in functions (map, int). In as much as Python has built-in functions, we can also define our own functions. In this section, we shall discuss the general form of a function in Python.

A Python function has the following syntax:

def function_name(arg1, arg2,...,argN):
    # function code

As seen above, a Python function begins with the def keyword, followed by the function’s name, parameter(s) in parenthesis(()), then a colon, and finally, the function code which is indented and usually contains a return statement that exits the function and passes back an expression to the caller.

To be more thorough, let’s consider the below function that multiplies two numbers and returns the result.

Function definition with annotations
Figure 2: Function definition with annotations

We can see that a function has the following key-parts

def keyword: The “def keyword” is used to write functions that generate a new object and assigns it to the function’s name. After the assignment, the function’s name now becomes a reference to the function object.

function name: The function’s name holds a reference to the function object once created by the def statement. This permits us to define functions once and call them in many parts of our code. In Python, an anonymous function doesn’t have a function’s name.

function parameters: When a function is defined to take in data, the parameters are used to hold that data and pass it into the function’s body.

Colon: The colon(:) is a cue for the function’s body. That is, the function body gets indented after the colon.

function code: The function code also called the function body contains indented statements that get executed when the function gets called. It typically contains a return statement that exits the function and determines the value to be returned to the caller.

Function Parameters And Arguments

A function caller can control the data that gets into a function using the function’s parameters. A function without parameters can’t receive data from the caller. As we shall see later in this section, parameters and arguments have different definitions, though arguably used to mean the same.

Function Parameters Vs Arguments

The terms parameter and argument are arguably used for the same thing. However, from a function’s perspective, a parameter is a placeholder (variable) that is placed inside parentheses in a function definition while an argument is a value that is passed to the function when it is called.

Example 2: Consider figure 2 above and the code below, the parameters here are x and y. But when we call the function with answer = multiply(3, 4) as seen below, we pass in the values 3 and 4 as arguments.

def multiply(x, y):
    print("Multiply {} and {}".format(x, y))
    result = x * y
    return result

if __name__ == "__main__":
    answer = multiply(3,4)
    print("Answer: ", answer) 

Output

Function Parameters Vs Arguments

Define Function Without Parameters

Before we delve into defining function parameters, it is worth noting that functions can be defined without parameters. In this case, data can’t be passed into the function by the caller.

Example 3: Define a function called display that takes in no arguments and prints the “Hello World!

def display(): # no parameters in ()
    print("Hello World!")

if __name__ == '__main__':
    display() # called without arguments

Output

Define Function without Parameters

Define Parameters With Default Values

In Python, if a function is defined with parameters and the caller doesn’t pass in arguments that match the number of parameters, then a TypeError will be raised.

Example 4: Check the sample code below.

# define function with two parameters 
def display(x, y):
    print("X: ", x)
    print("Y: ", y)
    
if __name__ == '__main__':
    # function called and passed only one argument
    display(4)

Output

Define Parameters with Default Values

At times, we will like to define our function with parameters but will expect some parameters to pass in some default values into the body of the function when we don’t provide them with arguments.

This can be achieved by giving default values to the respected parameters in the function definition.

Consider the code sample in example 4 above. When the function is called, only one argument is passed, which is given to the parameter x. However, y doesn’t receive any argument. To prevent Python from raising an exception when this happens, we can give parameter y a default value during definition.

Now, x becomes a non-default parameter and y becomes a default parameter.

Example 5: Give the parameter y a default value.

# define function with two parameters where ‘y’ is a default parameter
def display(x, y=0):
    print("X: ", x)
    print("Y: ", y)
    
if __name__ == '__main__':
    # function called and passed only one argument
    display(4)

Output

Parameters with default value

NB: While giving function parameters default values, be sure that the non-default parameters appear before any default parameters.

Define Parameters With *args

A function can take in as many positional arguments as possible. However, we need to be sure that the number of arguments passed should match the number of parameters defined in the function parenthesis.

Example 6: Say that we want to add a number of integers but we don’t know at run time how many integers we want to add. This can cause us a lot of trouble if we use positional parameters.

Check the sample code below.

# define function with 4 positional parameters 
def add(a, b, c , d):
    return a + b + c + d
    
if __name__ == '__main__':
    # call function with 4 arguments
    result1 = add(4,5,3,2)
    print(" 1 Result: ", result1)

    # call function with 6 arguments
    result2 = add(4,6,2,7,8,9)
    print(" 2 Result: ", result2

Output

Define Parameters With *args

From the above result, the first function call returns the result because of the four arguments that were passed match with the four defined parameters. However, the second function call raises a TypeError exception as six arguments were passed but the function expected four as per the number of parameters.

Example 7: We could overcome this by defining our function with a single parameter and call the function with a list of the integers to add. Check the below example.

# define function with 1 parameters 
def add(l):
    result = 0
    for items in l:
        result += items
    return result
    
if __name__ == '__main__':
    # call function with a list of 4 integers
    list1 = [4,5,3,2]
    result1 = add(list1)
    print(" 1 Result: ", result1)
    # call function with a list of 6 integers
    list2 = [4,6,2,7,8,9]
    result2 = add(list2)
    print(" 2 Result: ", result2)
)

Output

args add list

Though this works, it can become inconvenient as we will need to create a list of all the arguments before passing them to the function.

Example 8: The simplest way to deal with this is to use the *args that allows us to pass as many positional arguments without the need to know the count.

# define function with *args
def add(*args):
    result = 0
    # args becomes a tuple of all the arguments passed into this function.
    for items in args:
        result += items
    return result
    
if __name__ == '__main__':
    # call function with 4 argument integers
    result1 = add(4,5,3,2)
    print(" 1 Result: ", result1)
    # call function with 6 argument integers
    result2 = add(4,6,2,7,8,9)

Output

args - output

Example 9: If we have an iterable and we want to pass each item into our function that was defined with *args, then we can use the unpacking operator(*) to do so.

# define function with *args
def add(*args):
    result = 0
    # args becomes a tuple of all the arguments passed into this function.
    for items in args:
        result += items
    return result
    
if __name__ == '__main__':
    # define a list of integers
    list_ints = [4,5,3,2]
    # use the unpacking operator(*) to unpack the list.
    result = add(*list_ints)
    print("Result: ", result)

Output

args add unpack

NB: Few things to note here

  • args in *args is just a name and can be replaced with any name we want.
  • args is treated as a tuple in the function’s body and contains all the arguments given to the function.
  • *args should come after any non-default parameter and before any default parameters during the function definition.

Define Parameters With **kwargs

In the previous section, we saw *args. In this section, we shall look at **kwargs, which somehow works the same, but unlike *args that deal with positional arguments, **kwargs deals with keyword arguments.

Before we look at some examples, it’s worth noting that:

  • kwargs in **kwargs is just a name and can be replaced with any name.
  • kwargs is treated as a dictionary in the function’s body containing the keyword arguments passed to it.
  • **kwargs should be the last parameter during the function definition.

Example 10: The code below defines a function with **kwargs parameter, receives keyword arguments, and concatenates their values.

def concatenate(**kwargs):
    # kwargs is treated as a dictionary
    return ''.join(list(kwargs.values()))

if __name__=="__main__":
    # call function with keyword arguments
    result = concatenate(a="Software", b="Testing", c="Help")
    print("Result: ", result)

Output

kwargs concatenation unpack

Example 11: If we have a dictionary and we want to pass each key-value pair into our function that was defined with **kwargs, then we can use the unpacking operator(**) to do so.

def concatenate(**kwargs):
    # kwargs is treated as a dictionary
    return ''.join(list(kwargs.values()))

if __name__=="__main__":
    # define dictionary 
    dict_names = {'a':"Software", 'b':"Testing", 'c':"Help"}
    # use unpacking operator(**) to pass key-value pairs to function.
    result = concatenate(**dict_names)
    print("Result: ", result)

Output

_kwargs_concatenation_unpack

Functions Vs Methods

The terminologies function and method are sometimes used interchangeably. However, in software development, methods are simply functions defined in a class i.e. they are attached to an object and unlike functions, they can’t be called by name only.

For example, we have the Python built-in math module. After importing it, we can access its methods such as sqrt, exp, and more. These are called methods as they are defined in the module. But, they have all defined the same functions that we have been treating in this tutorial.

Example 12: Import the math module and use its appropriate method to find the square root of 44.

# import math module and access its methods
import math
# number to find the square root of
numb = 44
# use the math’s sqrt() method to find the square root.
sqrt_result = math.sqrt(numb)

print("Square root of {} is {}".format(numb, sqrt_result))

Output

Functions Vs Methods

Scope Of Variables

In a program, the variables may or may not be accessible in every part of the program. Variables can only be accessible in their scope and Python has four types of variable scope(Local, Enclosing, Global, Built-in) that build the foundation of the LEGB rule(more on this later).

Local Scope

A variable defined in a function is only accessible within that function and exists as long as the function is executing. Meaning we can’t access a function’s local variable outside its body.

Example 13: Consider the example below.

def website():
    # define a local variable
    name = "SoftwareTestingHelp"
    # access and print the local variable within the function body
    print("Website name is: ", name)

if __name__ == "__main__":
    # execute the function
    website()
    # Try to access and print the function's local variable outside its body.
    print("Website name is: ", name)

Output

local scope

From the output above, accessing the function’s local variable outside its body raised a NameError exception.

Enclosing Scope

Enclosing scope exists in nested functions i.e. a function defined inside another function.

As we shall see in the example below, in a nested function, the parent function holds its local scope(which is its child’s enclosing scope) while the child function holds its own local scope, and based on the LEGB rule, the Python interpreter looks up names in the below order.

Local -> Enclosing -> Global -> Built-in

This means, the parent can’t access its child’s local scope but a child can access its parent’s local scope(which is its enclosing scope) even though a child function is a member of its parent’s local scope.

Example 14: Consider the code below

def parent():
    # define parent's local variable(which is the child function’s enclosing scope)
    parent_age = 50

    def child():
        # define child's local variable
        child_age = 12

        # Access child's local variable  in child's body
        print("Child's age in Child scope: ", child_age)
        # Access parent's local variable in child's body
        print("Parent's age in Child scope: ", parent_age)
       
    # execute child's functions in parent's body 
    child()

    # Access parent's local variable in parent's body
    print("Parent's age in Parent scope: ", parent_age)

    print("-------------------------")

    # Access child's local variable in parent’s body
    print("Child's age in Parent scope: ", child_age)

if __name__ == "__main__":
    parent()

Output

enclosing scope

Global Scope

Variables defined at the top level of our script or module or program becomes global variables and are accessed anywhere within the program i.e. any function defined in that program can access these variables.

Example 15: Consider the example below.

# global variable defined
greeting = "Good morning "

# function 1
def greet_Kevin():
    name = "Kevin"
    # Access global variable
    print(greeting, name)

# function 2
def greet_Enow():
    name = "Enow"
    # Access global variable
    print(greeting, name)

if __name__ == '__main__':
    greet_Kevin()
    greet_Enow()

Output

global scope

NB: The Python interpreter first looks up the variable greeting in the function’s local scope, if not found, it looks at the enclosing scope, if nothing still, then it looks at the global scope which is actually where the variable is defined.

Global Keyword

We saw that a variable defined in a function is local to that function and is not accessible outside its body. The global keyword comes in when we want to access a function’s local variable outside its body i.e. making a function’s local variable global.

All we have to do is declare the specific variable with the global keyword as below.

global <variable_name>

Example 16: Let’s modify example 13 to make the function’s local variable global and access it outside its body.

def website():
    # make the local variable global
    global name
    # assign the variable
    name = "SoftwareTestingHelp"
    # access and print the local variable within the function body
    print("Website name inside function body : ", name)

if __name__ == "__main__":
    # execute the function
    website()
    # Try to access and print the function's local variable outside its body.
    print("Website name outside function body: ", name)

Output

global keyword

Built-in Scope

This scope is the largest in Python and it contains pre-built functions, reserved words, and other properties pre-defined in Python.

Based on the LEGB rule, the last scope the Python interpreter will look up names and if not found, a NameError is raised. This means that any variable defined in the built-in scope can be accessed anywhere in the program without being defined by us(unlike global scope).

Example 17: Round up the number 43.9853 to two decimal places.

def round_to_2_decimal(numb):
    # the function 'round()' is defined in the built-in scope.
    result = round(numb, 2)
    print("Result: ", result)

if __name__ == '__main__':
    x = 43.9853
    round_to_2_decimal(x)

Output

Built-in Scope

Function Return Statement

In Python, a return statement ends the execution of its function and returns a specific value to its caller.

Few things that we should know about Return statements are:

  • They can’t be used outside a function.
  • Any statement after a return statement is ignored.
  • A return statement without any expression returns None as the default.

Example 18: Create a function that takes in two numbers and returns their sum.

def calc(x, y):
    # return the sum of x and y.
    return x + y

if __name__ == '__main__':
    x = 43
    y = 5
    result = calc(x,y)
    print("Sum of {} and {} is : {}".format(x,y,result))

Output

return statement

Return Multiple Values

A return statement doesn’t only return a single value. It can ‘return’ multiple values defined in any data structure like tuple, list, dictionary, etc.

Example 19: Modify example 18 to return the sum and product of its two-argument numbers.

def calc(x, y):
    # return the sum and product of x and y as a tuple.
    return x + y, x * y

if __name__ == '__main__':
    x = 43
    y = 5
    result = calc(x,y)
    print("Sum of {} and {} is : {}".format(x,y,result[0]))
    print("Product of {} and {} is : {}".format(x,y,result[1]))

Output

Return multiple values

Return A Function

A return statement can also return a function. As we saw earlier in this tutorial, functions are first-order objects and higher-order that make them possible to be returned from a return statement.

Example 20: The code below defines a function that receives one argument and returns a function that takes in the second argument which then calculates the sum of the numbers.

def calc(x):
    # nest a function
    def add(y):
        # inner function returns sum of x and y
        return x + y
    # outer function return inner function
    return add

if __name__ == '__main__':
    x = 43
    y = 5
    # execute outer function
    add_x = calc(x)
    # execute inner function returned by outer function 
    add_xy = add_x(y)
    
    print("Sum of {} and {} is : {}".format(x,y,add_xy))

Output

return a function

Frequently Asked Questions

Q #1) Can you return a print statement in Python?

Answer: The print statement itself “prints” its content to the console and doesn’t return anything. So, returning a print statement will first execute the print statement and return whatever was returned from this print statement.

In a nutshell, returning a print statement will return None.

def return_print():
    # return a print statement
    return print("Hello")

if __name__ == "__main__":
    # executing this function will execute the print statement and return None.
    result = return_print()

    print("Result: ", result)

Output

print statement in python

Q #2) How do you end a function without returning in Python?

Answer: Python functions always return a value. If not explicitly defined, it will return None and exit the function.

Q #3) How many types of functions are there in Python?

Answer:

In Python, there are 3 types of function namely:

  • Built-in functions
  • User-defined functions
  • Anonymous functions.

More About Functions

A function is a block of code that is used to perform some specific actions. A function provides higher modularity and code reusability.

Functions help to break a large code into smaller modules.

Syntax:

def function_name(parameters): 
#Block of code or statements

Defining a Function

  • Function block should always begin with the keyword ‘def, followed by the function name and parentheses.
  • We can pass any number of parameters or arguments inside the parentheses.
  • The block of a code of every function should begin with a colon (:)
  • An optional ‘return’ statement to return a value from the function.

Example:

def my_function():
       print(“Hello Python”)

Python - defining function

Simply defining a function is useless unless you call it.

Calling a Function

Once the structure of a function is finalized, you can execute it by calling the function using the function name.

Example:

def my_function():
       print(“Hello Python”)
my_function()

Python - calling function

Output:

Hello Python

calling_function_output

Calling a Function using Parameters

We can define any number of parameters while defining a function.

Syntax:

def my_function(parameters): 

#Block of code or statements

Example:

def my_function(fname):
       print(“Current language is: “, fname)

my_function(“Python”)
my_function(“Java”)

Python - calling function with parameters

Output:

Current language is: Python
Current language is: Java

Python - calling function with parameters - output

Return Statement

A return statement is used to return a value from the function.

Example:

def additions(a, b):
       sum = a+b
       return sum

print(“Sum is: “, additions(2, 3))

Output:

Sum is: 5

Python - return statement

Output:

Python - return statement - output

Function Arguments

In python, we can call a function using 4 types of arguments:

  • Required argument
  • Keyworded argument
  • Default argument
  • Variable-length arguments

#1) Required Arguments

Required arguments are the arguments that are passed to a function in sequential order, the number of arguments defined in a function should match with the function definition.

Example:

def addition(a, b):
       sum = a+b
       print(“Sum of two numbers is:”, sum)

addition(5, 6)

Output:

Sum of two numbers is: 11

Python - required arguments

Output:

Python - required arguments - output

#2) Keyworded Arguments

When we use keyword arguments in a function call, the caller identifies the arguments by the argument name.

Example:

def language(lname):
       print(“Current language is:”, lname)

language(lname = “Python”)

Output:

Current language is: Python

Python - keyworded arguments

Output:

Python - keyworded arguments - output

#3) Default Arguments

When a function is called without any arguments, then it uses the default argument.

Example:

def country(cName = “India”):
       print(“Current country is:”, cName)

country(“New York”)
country(“London”)
country()

Output:

Current country is: New York
Current country is: London
Current country is: India

Python - default arguments

Output:

Python - default arguments - output

#4) Variable-length Arguments

If you want to process more arguments in a function than what you specified while defining a function, then these type of arguments can be used.

Example 1:

Non – Keyworded argument

def add(*num): 
       sum = 0
       for n in num: 
              sum = n+sum
       print(“Sum is:”, sum)

add(2, 5)
add(5, 3, 5)
add(8, 78, 90)

Output:

Sum is: 7
Sum is: 13
Sum is: 176

Python - variable length arguments Example 1

Python - variable length arguments Example 1 Output

Example 2:

Keyworded arguments

def employee(**data):
       for(key, value in data.items()):
              print(“The value {} is {}” .format(key,value))


employee(Name = “John”, Age = 20)
employee(Name = “John”, Age = 20, Phone=123456789)

Output:

Name is John
Age is 20

Name is John
Age is 20
Phone is 123456789

Python- variable length arguments Example 2

Output:

Python- variable length arguments Example 2 Output

Conclusion

In this tutorial, we looked at the user-defined functions which is a type of function in Python. We discussed some of its properties and saw why we should use functions.

We also looked at defining functions where we addressed: parameters, arguments, variable scopes, and return statements.

  • Functions help to divide a large program into smaller parts that help in code re-usability and size of the program.
  • Functions help in a better understanding of the code for the users as well.
  • Using Python input/output functions, we can get the input from the user during run-time or from external sources like text files, etc.

PREV Tutorial | NEXT Tutorial