# Topic covered
* Functions
* Built-in Functions
* Anonymous/lambda Functions
* map() function
* reduce() function
* filter() function
* eval() function
* User Defined Functions
* Return Statement
* Parameters & Arguments
* Positional arguments
* Keyword arguments
* Default arguments
* Variable length arguments
* Generators
* Iterable and Iterator in Python
* Create an Iterator Class
9. Functions
If a group of statements is repeatedly required then it is not recommended to write these statements everytime separately.
We have to define these statements as a single unit, and we can call that unit any number of times
based on our requirement without rewriting. This unit is nothing but function.
- The main advantage of functions is
code Reusability
. - Python supports 2 types of functions
- Built-in Functions
- User Defined Functions
9.1 Built-in Functions
The functions which are coming along with Python software automatically, are called built-in functions or pre-defined functions
Eg:
id() , type(), input(),
map(), reduce(), filter(), lambda(), eval()
9.2 User Defined Functions
The functions which are developed by programmer explicitly according to business requirements, are called user defined functions.
# Syntax
def function_name(parameters):
""" doc string"""
----
-----
return value
9.3 Return Statement
Function can take input values as parameters and executes business logic, and returns output
to the caller with return statement.
def add(x,y):
return x+y
result=add(10,20)
print("The sum is",result)
# Returning multiple values
def sum_sub(a,b):
sum=a+b
sub=a-b
return sum,sub
x,y=sum_sub(100,50)
print(x,y)
9.4 Parameters
Parameters are inputs to the function. If a function contains parameters, then at the time of calling, compulsory we should provide values otherwise, otherwise we will get error.
A parameter is the variable defined within the parentheses during function definition
.
# Here a,b are the parameters
def sum(a,b):
print(a+b)
sum(1,2)
9.5 Arguments
An argument is a value that is passed to a function when it is called.
It might be a variable, value or object passed to a function or method as input.
They are written when we are calling the function
def f1(a,b):
------
------
------
f1(10,20)
There are 4 types are actual arguments are allowed in Python.
- Positional arguments
- Keyword arguments
- Default arguments
- Variable length arguments
Positional arguments
The number of arguments and position of arguments must be matched. If we change the order then result may be changed.
def sub(a,b):
print(a-b)
sub(100,200) # -100
sub(200,100) # 100
Keyword arguments
Here the order of arguments is not important but number of arguments must be matched.
def wish(name, msg):
print("Hello", name, msg)
wish(name="Amrit", msg="Good Morning")
# Hello Amrit Good Morning
wish(msg="Good Morning", name="Amrit")
# Hello Amrit Good Morning
We can use both positional and keyword arguments simultaneously.
But first we have to take positional arguments
and then keyword arguments, otherwise we will get syntax-error.
def wish(name, msg):
print("Hello", name, msg)
wish("Amrit", "GM") # valid
wish("Amrit", msg="GM") # valid
wish(name="Amrit", "GM") # invalid
# SyntaxError: positional argument follows keyword argument
Default Arguments
Sometimes we can provide default values for our positional arguments.
def wish(name="Guest"):
print("Hello", name, "GoodMorning")
wish("Amrit")
# Hello Amrit Good Morning
wish()
# Hello Amrit Good Morning
- SyntaxError: non-default argument follows default argument
def wish(name="Guest", msg="Good Morning"): # valid
def wish(name, msg="Good Morning"): # valid
def wish(name="Guest", msg): # Invalid
Variable length arguments
Sometimes we can pass variable number of arguments
to our function,
such type of arguments are called variable length arguments.
We can declare a variable length argument with * symbol
as follows
def sum(*n):
total=0
for i in n:
total=total+i
print(total)
sum() # 0
sum(10) # 10
sum(10, 20) # 30
sum(10, 20, 30, 40) # 100
We can mix variable length arguments with positional arguments.
def f1(n1,*s):
print(n1, s)
f1(10) # 10 ()
f1(10,20) # 10 (20,)
f1(10, "A", 30) # 10 ('A', 30)
We can declare key word variable length arguments
also.
For this we have to use **
.
def display(**kwargs):
print(kwargs)
display(n1=10)
# {'n1': 10}
display(rno=100,name="Amrit")
# {'rno': 100, 'name': 'Amrit'}
- Using both
*args and **kwargs
in Python to call a function
def test7(*args , **kwargs) :
return args , kwargs
test7(2,3,4,5,a= 34, b = 98)
# ((2, 3, 4, 5), {'a': 34, 'b': 98})
9.6 Anonymous/lambda Functions
Sometimes we can declare a function without any name, such type of nameless functions are called
anonymous/lambda
functions
The main purpose of anonymous function is just for instant
use(i.e. for one time usage
)
AKA lambda functions
or shorthand function
# Syntax
lambda argument_list : expression
print((lambda x: x + 1)(2)) # 3
s = lambda n:n*n
print(s(4)) # 64
s = lambda a,b:a+b
print(s(2, 3)) # 5
s = lambda a,b:a if a>b else b
print(s(10,20)) # 20
print(s(100,200)) # 200
print((lambda x, y, z=3: x + y + z)(1, 2))
Note
Lambda Function internally returns expression value and we are not required to write return statement explicitly
Sometimes we can pass function as argument to another function. In such cases lambda functions are the best choice.
We can use lambda functions very commonly with filter(), map() and reduce()
functions,
because these functions expect function as argument.
9.7 map() function
map()
function returns a map object(which is an iterator) of the results after applying
the given function to each item of a given iterable (list, tuple etc.)
# str to int
num = ['1', '2', '3']
res = list(map(int, num))
print(res)
# Square
def square(number):
return number ** 2
numbers = [1, 2, 3, 4, 5]
print(list(map(square, numbers)))
# Square using map and lambda
print(list(map(lambda x:x*x, numbers)))
first_it = [1, 2, 3]
second_it = [4, 5, 6, 7]
print(list(map(pow, first_it, second_it)))
# x- y
print(list(map(lambda x, y: x - y, [2, 4, 6], [1, 3, 5])))
# [1, 1, 1]
print(list(map(lambda x, y, z: x + y + z, [2, 4], [1, 3], [7, 8])))
# [10, 15]
# Eg 5
string_it = ["processing", "strings", "with", "map"]
print(list(map(str.upper, string_it)))
# ['PROCESSING', 'STRINGS', 'WITH', 'MAP']
with_spaces = ["processing ", " strings", "with ", " map "]
print(list(map(str.strip, with_spaces)))
# ['processing', 'strings', 'with', 'map']
with_dots = ["processing..", "...strings", "with....", "..map.."]
print(list(map(lambda s: s.strip("."), with_dots)))
# ['processing', 'strings', 'with', 'map']
# Eg 6
import re
def remove_punctuation(word):
return re.sub(r'[!?.:;,"()-]', "", word)
text = """Some people, when ,,confronted... with a problem, think"""
words = text.split()
print(list(map(remove_punctuation, words)))
9.8 reduce() function
reduce() function reduces sequence of elements
into a single element by applying the specified function.
reduce() function present in functools module and hence we should write import statement.
reduce(function, sequence)
from functools import *
l = [10,20,30,40,50]
result=reduce(lambda x,y:x+y,l)
print(result) # 150
l = [1,2,3,4,5,4]
# Does not work on 3 variable
reduce(lambda x , y , z : x+y+z , l) # TypeError
reduce(lambda x , y : x+y , [1])
# 1
# Biggest emement in list
reduce(lambda x,y : x if x> y else y , l)
# 5
9.9 filter() function
We can use filter() function to filter values
from the given sequence
based on some condition.
filter(function, sequence)
-
where function argument is responsible to perform conditional check
sequence can be list or tuple or string.
# Working of filter()
def check_even(number):
if number % 2 == 0:
return True
return False
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
list(filter(check_even, numbers))
# Output: [2, 4, 6, 8, 10]
# Using Lambda Function Inside filter()
list(filter(lambda x: (x%2 == 0), numbers))
list(filter(lambda x: True if x%2==0 else False, numbers))
# [2, 4, 6, 8, 10]
l2 = ["sudh" , "pwskills" , "kumar" , "bengalore" , "krish"]
print(list(filter(lambda x : len(x) < 6 , l2)))
9.10 eval() function
- The eval function evaluates the String like a
python expression
and returns the result as an integer. eval(expression, globals=None, locals=None)
- The globals must be represented as a dictionary and the locals as a mapped object.
x = 1
print(eval('x + 1'))
print(eval("1024 + 1024"))
code = compile("5 + 4", "<string>", "eval")
print(eval(code))
print()
x = 100
print(eval("x + 10", {"x": x}))
print(eval("x + y", {"x": x, "y": x}))
9.10 Generators
Generator is a function which is responsible to generate a sequence of values
.
We can write generator functions just like ordinary functions, but it uses yield keyword
to return values.
def simpleGeneratorFun():
yield 1
yield 2
yield 3
for value in simpleGeneratorFun():
print(value, end=' ')
# 1 2 3
x = simpleGeneratorFun()
print(list(x))
# [1, 2, 3]
Advantages of Generator Functions
- When compared with class level iterators, generators are very easy to use
- Improves
memory utilization
andperformance.
- Generators are the best suitable for reading data from large number of large files
- Generators work great for web scraping and crawling.
We will get MemoryError
in this case because all these values are required to store in the memory.
# Normal Collection --> []
l=[x*x for x in range(10000000000000000)]
print(l[0])
We won't get any MemoryError
because the values won’t be stored at the beginning
# Generators --> ()
g=(x*x for x in range(10000000000000000))
print(next(g))
# 0
9.11 Iterable and Iterator in Python
- Iteration means to access each item of something one after another generally
using a loop
- list, tuples, dictionaries, etc. –> all are iterables
- One important property it has
- an
__iter__()
method oriter()
method - which allows any iterable to return an iterator object.
- an
iter()
andnext()
# list of cars
cars = ['Audi', 'BMW', 'Jaguar', 'Kia', 'MG', 'Skoda']
# get iterator object using the iter() / __iter__() method
cars_iter = iter(cars)
cars_iter = cars.__iter__()
# use the next / __next__() method to iterate through the list
print(next(cars_iter))
# OP: Audi
print(cars_iter.__next__())
# OP: BMW
Create an Iterator Class
- To create an object/class as an iterator you have to implement the methods
__iter__() and __next__()
to your object. - To prevent the iteration to go on forever, we can use the
StopIteration
statement.
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
if self.a <= 3:
x = self.a
self.a += 1
return x
else:
raise StopIteration
my_class = MyNumbers()
my_iter = iter(my_class)
print(next(my_iter))
print(next(my_iter))
print(next(my_iter))
print(next(my_iter))
print(next(my_iter))