Chapter 2
Chapter 2
Python Functions
Python Functions is a block of statements that return the specific
task. The idea is to put some commonly or repeatedly done tasks
together and make a function so that instead of writing the same
code again and again for different inputs, we can do the function
calls to reuse code contained in it over and over again.
Some Benefits of Using Functions
Increase Code Readability
Increase Code Reusability
Python Function Declaration
The syntax to declare a function is:
def fun():
print("Welcome to GFG")
Output:
Welcome to GFG
Python Function with Parameters
If you have experience in C/C++ or Java then you must be thinking
about the return type of the function and data type of arguments.
That is possible in Python as well (specifically for Python 3.5 and
above).
Defining and calling a function with parameters
def function_name(parameter: data_type) -> return_type:
"""Docstring"""
# body of the function
return expression
The following example uses arguments and parameters that you will
learn later in this article so you can come back to it again if not
understood.
Python3
return num3
# Driver code
num1, num2 = 5, 15
ans = add(num1, num2)
print(f"The addition of {num1} and {num2} results {ans}.")
Output:
The addition of 5 and 15 results 20.
Note: The following examples are defined using syntax 1, try to
convert them in syntax 2 for practice.
Python3
Output:
False True
Python Function Arguments
Arguments are the values passed inside the parenthesis of the
function. A function can have any number of arguments separated
by a comma.
In this example, we will create a simple function in Python to check
whether the number passed as an argument to the function is even
or odd.
Python3
Output:
even
odd
Types of Python Function Arguments
Python supports various types of arguments that can be passed at
the time of the function call. In Python, we have the following 4
types of function arguments.
Default argument
Keyword arguments (named arguments)
Positional arguments
Arbitrary arguments (variable-length arguments *args
and **kwargs)
Let’s discuss each type in detail.
Default Arguments
A default argument is a parameter that assumes a default value if a
value is not provided in the function call for that argument. The
following example illustrates Default arguments.
Python3
Output:
x: 10
y: 50
Like C++ default arguments, any number of arguments in a function
can have a default value. But once we have a default argument, all
the arguments to its right must also have default values.
Keyword Arguments
The idea is to allow the caller to specify the argument name with
values so that the caller does not need to remember the order of
parameters.
Python3
Output:
Geeks Practice
Geeks Practice
Positional Arguments
We used the Position argument during the function call so that the
first argument (or value) is assigned to name and the second
argument (or value) is assigned to age. By changing the position, or
if you forget the order of the positions, the values can be used in the
wrong places, as shown in the Case-2 example below, where 27 is
assigned to the name and Suraj is assigned to the age.
Python3
Output:
Case-1:
Hi, I am Suraj
My age is 27
Case-2:
Hi, I am 27
My age is Suraj
Arbitrary Keyword Arguments
In Python Arbitrary Keyword Arguments, *args, and **kwargs can
pass a variable number of arguments to a function using special
symbols. There are two special symbols:
*args in Python (Non-Keyword Arguments)
**kwargs in Python (Keyword Arguments)
Example 1: Variable length non-keywords argument
Python3
Output:
Hello
Welcome
to
GeeksforGeeks
Example 2: Variable length keyword arguments
Python3
def myFun(**kwargs):
for key, value in kwargs.items():
print("%s == %s" % (key, value))
# Driver code
myFun(first='Geeks', mid='for', last='Geeks')
Output:
first == Geeks
mid == for
last == Geeks
Docstring
The first string after the function is called the Document string
or Docstring in short. This is used to describe the functionality of the
function. The use of docstring in functions is optional but it is
considered a good practice.
The below syntax can be used to print out the docstring of a
function:
Syntax: print(function_name.__doc__)
Example: Adding Docstring to the function
Python3
def evenOdd(x):
"""Function to check if the number is even or odd"""
if (x % 2 == 0):
print("even")
else:
print("odd")
Output:
Function to check if the number is even or odd
Python Function within Functions
A function that is defined inside another function is known as
the inner function or nested function. Nested functions can
access variables of the enclosing scope. Inner functions are used so
that they can be protected from everything happening outside the
function.
Python3
# Python program to
# demonstrate accessing of
# variables of nested functions
def f1():
s = 'I love GeeksforGeeks'
def f2():
print(s)
f2()
# Driver's code
f1()
Output:
I love GeeksforGeeks
Anonymous Functions in Python
In Python, an anonymous function means that a function is without a
name. As we already know the def keyword is used to define the
normal functions and the lambda keyword is used to create
anonymous functions.
Python3
print(cube(7))
print(cube_v2(7))
Output:
343
343
Recursive Functions in Python
Recursion in Python refers to when a function calls itself. There are
many instances when you have to build a recursive function to
solve Mathematical and Recursive Problems.
Using a recursive function should be done with caution, as a
recursive function can become like a non-terminating loop. It is
better to check your exit statement while creating a recursive
function.
Python3
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n - 1)
print(factorial(4))
Output
24
Here we have created a recursive function to calculate the factorial
of the number. You can see the end statement for this function is
when n is equal to 0.
Return Statement in Python Function
The function return statement is used to exit from a function and go
back to the function caller and return the specified value or data
item to the caller. The syntax for the return statement is:
return [expression_list]
The return statement can consist of a variable, an expression, or a
constant which is returned at the end of the function execution. If
none of the above is present with the return statement a None
object is returned.
Example: Python Function Return Statement
Python3
def square_value(num):
"""This function returns the square
value of the entered number"""
return num**2
print(square_value(2))
print(square_value(-4))
Output:
4
16
Pass by Reference and Pass by Value
One important thing to note is, in Python every variable name is a
reference. When we pass a variable to a function, a new reference
to the object is created. Parameter passing in Python is the same as
reference passing in Java.
Python3
Output:
[20, 11, 12, 13, 14, 15]
When we pass a reference and change the received reference to
something else, the connection between the passed and received
parameters is broken. For example, consider the below program as
follows:
Python3
def myFun(x):
Output:
[10, 11, 12, 13, 14, 15]
Another example demonstrates that the reference link is broken if
we assign a new value (inside the function).
Python3
def myFun(x):
Output:
10
Exercise: Try to guess the output of the following code.
Python3
# Driver code
x = 2
y = 3
swap(x, y)
print(x)
print(y)
Output:
2
3
Iterators in Python
An iterator in Python is an object that is used to iterate over iterable
objects like lists, tuples, dicts, and sets. The Python iterators object
is initialized using the iter() method. It uses the next() method for
iteration.
1. __iter__(): The iter() method is called for the initialization of
an iterator. This returns an iterator object
2. __next__(): The next method returns the next value for the
iterable. When we use a for loop to traverse any iterable
object, internally it uses the iter() method to get an iterator
object, which further uses the next() method to iterate over.
This method raises a StopIteration to signal the end of the
iteration.
Python iter() Example
Python3
string = "GFG"
ch_iterator = iter(string)
print(next(ch_iterator))
print(next(ch_iterator))
print(next(ch_iterator))
Output :
G
F
G
Python3
# Constructor
def __init__(self, limit):
self.limit = limit
# Prints nothing
for i in Test(5):
print(i)
Output:
10
11
12
13
14
15
Output:
List Iteration
geeks
for
geeks
Tuple Iteration
geeks
for
geeks
String Iteration
G
e
e
k
s
Dictionary Iteration
xyz 123
abc 345
Iterable vs Iterator
Python iterable and Python iterator are different. The main
difference between them is, iterable in Python cannot save the state
of the iteration, whereas in iterators the state of the current iteration
gets saved.
Note: Every iterator is also an iterable, but not every iterable is an
iterator in Python.
Read more – Difference between iterable and iterator.
Iterating on an Iterable
Python3
Output:
a
b
c
d
e
Iterating on an iterator
Python3
Output:
Inside loop:
a
b
c
Outside loop:
D,e
enerators in Python
A Generator in Python is a function that returns an iterator using the
Yield keyword. In this article, we will discuss how the generator
function works in Python.
Generator Function in Python
A generator function in Python is defined like a normal function, but
whenever it needs to generate a value, it does so with the yield
keyword rather than return. If the body of a def contains yield, the
function automatically becomes a Python generator function.
Create a Generator in Python
In Python, we can create a generator function by simply using the
def keyword and the yield keyword. The generator has the following
syntax in Python:
def function_name():
yield statement
Example:
In this example, we will create a simple generator that will yield
three integers. Then we will print these integers by using Python for
loop.
Python3
Output:
1
2
3
Generator Object
Python Generator functions return a generator object that is
iterable, i.e., can be used as an Iterator. Generator objects are used
either by calling the next method of the generator object or using
the generator object in a “for in” loop.
Example:
In this example, we will create a simple generator function in Python
to generate objects using the next() function.
Python3
# A generator function
def simpleGeneratorFun():
yield 1
yield 2
yield 3
# x is a generator object
x = simpleGeneratorFun()
# Iterating over the generator object using next
# In Python 3, __next__()
print(next(x))
print(next(x))
print(next(x))
Output:
1
2
3
Example:
In this example, we will create two generators for Fibonacci
Numbers, first a simple generator and second generator using a for
loop.
Python3
Output:
0
1
1
2
3
# generator expression
generator_exp = (i * 5 for i in range(5) if i%2==0)
for i in generator_exp:
print(i)
Output:
0
10
20
Recursion in Python
The term Recursion can be defined as the process of defining
something in terms of itself. In simple words, it is a process in which
a function calls itself directly or indirectly.
# Recursive function
def recursive_fibonacci(n):
if n <= 1:
return n
else:
return(recursive_fibonacci(n-1) + recursive_fibonacci(n-2))
n_terms = 10
Output
Fibonacci series:
0
1
1
2
3
5
8
13
21
34
Example 2: The factorial of 6 is denoted as 6! = 1*2*3*4*5*6 =
720.
Python3
# Recursive function
def recursive_factorial(n):
if n == 1:
return n
else:
return n * recursive_factorial(n-1)
# user input
num = 6
Output
Factorial of number 6 = 720
What is Tail-Recursion?
A unique type of recursion where the last procedure of a function is
a recursive call. The recursion may be automated away by
performing the request in the current stack frame and returning the
output instead of generating a new stack frame. The tail-recursion
may be optimized by the compiler which makes it better than non-
tail recursive functions.
Is it possible to optimize a program by making use of a tail-
recursive function instead of non-tail recursive function?
Considering the function given below in order to calculate the
factorial of n, we can observe that the function looks like a tail-
recursive at first but it is a non-tail-recursive function. If we observe
closely, we can see that the value returned by Recur_facto(n-1) is
used in Recur_facto(n), so the call to Recur_facto(n-1) is not the last
thing done by Recur_facto(n).
Python3
if (n == 0):
return 1
return n * Recur_facto(n-1)
Output
720
We can write the given function Recur_facto as a tail-recursive
function. The idea is to use one more argument and in the second
argument, we accommodate the value of the factorial. When n
reaches 0, return the final value of the factorial of the desired
number.
Python3
if (n == 0):
return a
return Recur_facto(n - 1, n * a)
Output
720
print(shout('Hello'))
print(yell('Hello'))
Output:
HELLO
HELLO
In the above example, a function object referenced by shout and
creates a second name pointing to it, yell.
Passing Function as an argument to other function
Functions are like objects in Python, therefore, they can be passed
as argument to other functions. Consider the below example, where
we have created a function greet which takes a function as an
argument. Example:
def whisper(text):
return text.lower()
def greet(func):
# storing the function in a variable
greeting = func("Hi, I am created by a function \
passed as an argument.")
print(greeting)
greet(shout)
greet(whisper)
Output:
HI, I AM CREATED BY A FUNCTION PASSED AS AN ARGUMENT.
hi, i am created by a function passed as an argument.
Returning function
As functions are objects, we can also return a function from another
function. In the below example, the create_adder function returns
adder function. Example:
def create_adder(x):
def adder(y):
return x + y
return adder
add_15 = create_adder(15)
print(add_15(10))
Output:
25
Decorators
Decorators are the most common use of higher-order functions in
Python. It allows programmers to modify the behavior of function or
class. Decorators allow us to wrap another function in order to
extend the behavior of wrapped function, without permanently
modifying it. In Decorators, functions are taken as the argument into
another function and then called inside the wrapper
function. Syntax:
@gfg_decorator
def hello_decorator():
.
.
.
The above code is equivalent to –
def hello_decorator():
.
.
.
hello_decorator = gfg_decorator(hello_decorator)
In the above code, gfg_decorator is a callable function, will add some
code on the top of some another callable
function, hello_decorator function and return the wrapper
function. Example:
# defining a decorator
def hello_decorator(func):
return inner1