Home

Functions in Python

Function is a set of organized lines of code that performs a specific, well defined task.

It is used reduce the number of lines of code and improve reusability.

Syntax:

def function_name(parameters):  # function definition  
    Statements
    return value(s)

...  
...  
function_name(parameters) # Caller

Return statement:

return

Returns back a value as specified. It marks the end of a function

Fruitful function

A fruitful function is a function that returns a value

IN [1]

# Example 1:
def add(a, b): # Function Definition
    return a + b # returns the sum
x = int(input())
y = int(input())
print(add(x, y)) # Function Calling
# Input:
# 12
# 13

stdin

 12
 13

stdout

25

Naming a function

Like variables, python functions should also be in lower_snake_case

One of the more universal, yet simple rules is: Function names should be verbs if the function changes the state of the program, and nouns if they’re used to return a certain value.

  1. Self-explanatory names: a function get_name() will tell the developer what it returns as well as set_address(), is_male(), etc.
  2. Short: a function name must be as short as possible so that it’s simple to type as well as easy to remember. A function get_number_of_pages_in_the_book() is not good, something like get_book_page_count() is better.
  3. Use of prefixes: use prefixes in the functions such as get_name(), set_name(), etc.

The most important thing to note is to follow a constant naming convention throughout the function

Lambda function (Inline or Anonymous function):

One liner of a function. It is created for use at one point or one statememt and is not intended to be named and stored.

Syntax:

lambda parameters: Statement

IN [9]

# Example 1

def is_even(x):
    return x % 2 == 0 # One line function to check if even

a = int(input())
print("From is_even(x):", is_even(a))
print("From lambda:", (lambda x: x % 2 == 0)(a)) # Equivalent lambda function

# Input: 10

stdin

 10

stdout

From is_even(x): True
From lambda: True

The lambda function is generally created for use with iterables where the function is applied to several values but at only once (that part of the code).

The usual places include maps, filter and keys for sorting for any iterable. Visit Lists or Tuples to know more on them

Recursion:

Recursion is a method of solving a problem where the solution depends on solutions to smaller instances of the same problem.

Recursive function:

A function that performs recursion.

A recursive function calls itself repeatedly by dividing the problem into sub problems until the solution is obtained for the smallest sub-problem.

def function(paramters1):
    function(parameters2) # Recursive calling

IN [14]

# Example using factorial (n! = 1 * 2 * 3 ... n) n! = n * (n-1)!
def factorial(n):
    if -1<n<=1: return 1 # End of recursion
    else: return n * factorial(n-1) # recursive calling

n = int(input())
print(factorial(n))
# Input: 6

stdin

 6

stdout

720

Breaking down of problem:

n = 6  
n <= 1 False  
6 * factorial(5)  

n = 5  
n <= 1 False  
5 * factorial(4)  

n = 4  
n <= 1 False  
4 * factorial(3)  

n = 3  
n <= 1 False  
3 * factorial(2)  

n = 2  
n <= 1 False  
2 * factorial(1)  

n = 1  
n <= 1 (n==1) True  
1

Building up:

1
2 * 1  
3 * 2 * 1  
4 * 3 * 2 * 1  
5 * 4 * 3 * 2 * 1  
6 * 5 * 4 * 3 * 2 * 1  

720

You can find the steps in recursion below
The ‘|’ line indicates the same level of recursive call

IN [5]

# The indent paramter defines the offset of output. This program is to understand recursion only.
def fact(n, indent=''):
    print(indent, n, sep='')
    if 0 <= n <= 1: return 1
    else:
        fac = n * fact(n-1, indent + "|\t")
        print(indent, fac, sep='')
        return fac

fact(6)

stdout

6
|   5
|   |   4
|   |   |   3
|   |   |   |   2
|   |   |   |   |   1
|   |   |   |   2
|   |   |   6
|   |   24
|   120
720

Function Arguments or Parameters: (args or params)

Values passed into a function. They are optional

Types:
  1. Required Arguments
  2. Keyword Arguements
  3. Default Arguments
  4. Variable length Arguments

1. Required Arguments:

Positional Arguments. These are arguments required to execute a function.
The number of required arguments should be equal to the number of arguments passed. If not, it will result in error.

IN [29]

# Example 
def add(a, b): # Function Definition - no. of required arguments
    return a+b # returns the sum
x = int(input())
y = int(input())
print(add(x, y)) # Function Calling - no. of args passed

# Input:
# 12
# 23

stdin

 12
 23

stdout

35

IN [30]

#Example
# Example 
def add(a, b): # Function Definition - no. of required arguments
    return a+b # returns the sum
x = int(input())
y = int(input())
print(add(x)) # Function Calling - no. of args passed < no. of required args

stdin

 10
 23

Error


Traceback (most recent call last):

  File "D:\Programming\Python\Jupyter Notebooks\Python_Programming_Notes\temp.py", line 7, in <module>

    print(add(x)) # Function Calling - no. of args passed < no. of required args

TypeError: add() missing 1 required positional argument: 'b'

2. Keyword arguments (kwargs):

These arguments are not positional but are required.

IN [20]

# Example 2
def add(a, b): # Function Definition - Parameters
    print(a, b)
    return a+b # returns the sum


x = int(input())
y = int(input())
print(add(b = x, a = y)) # Function Calling - Keywords are names of params used in definition
# Input: 10
# 23

stdin

 10
 23

stdout

23 10
33

3. Default arguments:

Arguments which are optional. They have values by default.

IN [31]

#Example 
def add(a, b = 0): # Function Definition - b is default args
    print(a, b)
    return a+b # returns the sum
x = int(input())
y = int(input())

# b given in function call
print('B given')
print(add(x, y)) # Function Calling

print()

# b not given in function call
print('B not given default = 0')
print(add(x)) # Function Calling

# Input: 12
# 23

stdin

 12
 23

stdout

B given
12 23
35

B not given default = 0
12 0
12

Defining or indicating the difference in the type of args:

From python 3.8, ‘/’ is used to Separate positional args from non positional.

IN [32]

# Example 
def add(a, /, b=0): # Function Definition
    return a+b # returns the sum
x = int(input())
y = int(input())
print(add(x)) # Function Calling 
# Input: 10
# 23

stdin

 10
 23

stdout

10

4. Variable Length Arguments:

Args that are used when the number of arguments is not known. The arguments passed are stored as a tuple. The arguments that start with ‘ * ‘ indicate Variable length arguments and are called gather

IN [2]

#Example
# Example 
def add(a, *b): # Function Definition -  * indicates variable length arguments
    print(b)
    return a + sum(b) # returns the sum; sum is a built in function that returns sum of elements in an iterable
x = int(input())
y = int(input())
# 2 arguments
print(add(x, y))
print()
# 3 args
print(add(x, y, 10))
print()
# 4 args
print(add(x, y, 10, 20)) # Function Calling - no. of args passed

# Input: 10
# 23

stdin

 10
 23

stdout

(23,)
33

(23, 10)
43

(23, 10, 20)
63

Types:

  1. *args
  2. **kwargs

1. *args:

Variable length arguements that are most commonly used. Stores the values as tuple

2. **kwargs:

Variable length arguments of the form key = value. Stores the values as key-value mapping or dictionary.

IN [3]

#kwargs example
def kwargs_ex(**a):
    print(a)
    for k, v in a.items():
        print(f"{k} = {v}")

kwargs_ex(x=2, y=3)

stdout

{'x': 2, 'y': 3}
x = 2
y = 3

Scope of variable:

The part of code where a variable can be accessed. Scopes: 1. Global Variable 2. Local Variable

1. Global Variable:

Variable that can be acessed in any part of the program.

2. Local Variable:

Variable that can be accessed only inside a specific block or part of a program.

IN [7]

#Example
def add(a, b): 
    c = a+b
    print(c)
    #return a+b

def printf():
    print(k)

x = int(input('x:'))
y = int(input('y:'))
add(x,y)
print('Hello')
s = 10
z = -100
for i in range(5):
    k = 'Hello'
    print(k)
print(x,y,s,z)
printf()
print(k)
print(i)
print(c)

# Input:
# 10
# 23

stdin

x: 10
y: 23

stdout

33
Hello
Hello
Hello
Hello
Hello
Hello
10 23 10 -100
Hello
Hello
4

Error

x:
Traceback (most recent call last):

  File "D:\Programming\Python\Jupyter Notebooks\Python_Programming_Notes\temp.py", line 10, in <module>

    x = int(input('x:'))

ValueError: invalid literal for int() with base 10: 'x: 10'

IN [9]

def printf(): # Function definition
    global k
    k = 'Hi' #Local Variable Gloablized
    print(k)

for i in range(5):
    k = 'Hello' # Global Variable
    print(k) 

printf()
print(k)

stdout

Hello
Hello
Hello
Hello
Hello
Hi
Hi

Docstrings in Function:

Docstrings are most commonly used in a function. They act as descriptor of function, i.e., they describe the function.

Calling docstings:

function_name.__doc__

IN [1]

def fn():
    '''This is a docstring'''
print(fn.__doc__) # Calls docstring

stdout

This is a docstring

Recursion vs Iteration:

Recursion involves calling function repeatedly to breakdown a problem.
Iteration is solving the problem by breaking down using loops.

Recursion is a easy way to solve a problem. But it is a bit time consuming. Iteration is hard coding but is efficient in solving the problems.

This brings in a new programming stream called Dynamic Programming.

Functions seen so far:

  1. print
  2. input
  3. int
  4. float

1. print:

Syntax:

print(values, end="\n", sep" ")

IN [3]

print(1,2,3, sep = "") # no separation between the values

stdout

123

IN [4]

print(1,2,3)

stdout

1 2 3

IN [5]

print(1,2,3, sep = '\t')

stdout

1   2   3

IN [6]

print(1,2,3)
print(4,5)

stdout

1 2 3
4 5

IN [7]

print(1,2,3, end='')# end of print is <none>
print(4,5)

stdout

1 2 34 5

IN [8]

print(1,2,3, end=' ') # end of print is <space>
print(4,5)

stdout

1 2 3 4 5

2. input:

Syntax:

input(prompt="")

IN [10]

n = input()

# Input: 20

stdin

 20

IN [11]

a = input(prompt = 'Prompt')

# Input: 10

stdin

Prompt 10

3. int:

Syntax:

int(x, base = 10)

IN [13]

int('10')

IN [14]

b = '110'
int(b, 2)

IN [15]

x = '7af'
int(x, 16)

IN [17]

o = '75'
int(o, 8)

4. float:

Syntax:

float(x = 0)

IN [20]

float()

IN [21]

float ('1.2')

IN [22]

float(1)

IN [24]

float('12') 

Multiple Functions with same name:

Python does not allows multiple functions with different parameters with same name. If so exist, the last function definition replaces the first.

IN [25]

def fn():
    return 'Hi'
def fn(x,y):
    return x+y
print(fn())
print(fn(10, 5))

Error


Traceback (most recent call last):

  File "D:\Programming\Python\Jupyter Notebooks\Python_Programming_Notes\temp.py", line 5, in <module>

    print(fn())

TypeError: fn() missing 2 required positional arguments: 'x' and 'y'

Gather vs Scatter:

Argument given to var. args are gathered and stored together to form a tuple. This is called gather.

Argument given as a list/tuple is split across required variable. This is called scatter

IN [2]

#Example
def add(a, *b): # Function Definition 
    print(a, b)
    return a + sum(b) # returns the sum; sum is a built in function that returns sum of elements in an iterable

l = list(map(int, input().split()))
print(add(*l)) # Function Calling

# Input: 10
# 23
# 30
# 40

stdin

 10 23 30 40

stdout

10 (23, 30, 40)
103

Higher Order Functions or Function Decorators:

A function returning another function is called a higher order function

def function1(params):
    def function2(params):
        Statements

    return function2

IN [13]

def deco(k): # Higher order function / decorator
    def multiple(n):
        return n*k
    return multiple

second_multiple = deco(2)
n = int(input("Enter a num\n"))
print(second_multiple(n))

stdin

Enter a num
 6

stdout

12