0% found this document useful (0 votes)
11 views43 pages

Unit 3 Functions

This document provides an overview of functions in Python, including their types (built-in and user-defined), syntax, and execution flow. It covers advanced topics such as keyword arguments, default values, variable arguments, recursion, and the use of global, local, and nonlocal variables. Additionally, it introduces lambda functions, higher-order functions, and generators, explaining their usage and providing examples.

Uploaded by

bbb403368
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views43 pages

Unit 3 Functions

This document provides an overview of functions in Python, including their types (built-in and user-defined), syntax, and execution flow. It covers advanced topics such as keyword arguments, default values, variable arguments, recursion, and the use of global, local, and nonlocal variables. Additionally, it introduces lambda functions, higher-order functions, and generators, explaining their usage and providing examples.

Uploaded by

bbb403368
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 43

Unit-3

Functions

Mr. Nilesh Parmar


Assistant Professor, Dept. of Computer Engg.
UVPCE, Ganpat University, Mehsana
Function
• Function provides reusability of code in very effective manner.
• There are 2 types of functions: 1) built-in 2) user defined
• We have seen many built-in functions for list, tuple, string like- max(),
min(), sum() and len() etc.
• Now, We will understand user-defined functions
• A function definition starts with ‘def’ keyword. Function syntax is given
below:
def function_name(list of parameters):
body of function
[return statement] (optional)
Cntd…
• Example:
def max_val(x,y):
if x>y:
return x
else:
return y
t=max_val(6,2)
print (t)
Output: 6
• Note: Function won’t be executed until, it is called.
Function: flow of execution
1) Before bounding actual parameter to formal parameter, actual parameters are
evaluated:
ex: max(3+4, t)
2) Point of execution: execution control moves from point of invocation to first
statement in body of function.
3) Function is executed until either when ‘return’ comes or there are no more
statements to execute.
i) If there is no return statement, return value is None
ii) If there is no expression after return statement, it returns None
iii) If there is return with a expression, value of expression becomes the
value of function invocation.
4) Point of execution is transferred back to code immediately following the
invocation
Keyword Arguments and Default Values
• Actual arguments: Arguments written in the function calling
• Formal parameters: Arguments written in function definition

• Types of formal parameters: 1) positional 2) keyword arguments


1) Positional: First parameter is bound to first argument, second is bound to
second argument and so on.
2) Keyword arguments: Formal parameters are bound to actual arguments
using name of formal parameters.
Note: positional argument cannot follow keyword argument. That means,
once you start writing keyword argument, you can not use positional
argument after that. If you do this, it will produce an error. Let’s understand
this point using an example.
• Example:
def printName(firstName, lastName, reverse):
if reverse:
print (lastName + ', ' + firstName)
else:
print (firstName, lastName)
printName('Olga', 'Puchma', False)
printName('Olga', 'Puchma', reverse = False)
printName('Olga', lastName = 'Puchma', reverse = True)
printName(lastName='Puchma', firstName='Olga', reverse=False)
#printName(lastName='Puchma','Olga', False) #Error: positional argument follows keyword argument.

Output: Olga Puchma


Olga Puchma
Puchma, Olga
Default values
• Default values allow programmers to call a function with fewer than the specified
number of arguments. For example,
def printName(firstName, lastName, reverse = False):
if reverse:
print(lastName + ', ' + firstName)
else:
print(firstName, lastName)
printName('Olga', 'Puchma')
printName('Olga', 'Puchma', True)
printName('Olga','Puchma', reverse = True)

Output:
Olga Puchma
Puchma, Olga
Variable arguments
• The special syntax *args in function definitions in python is used to pass a
variable number of arguments to a function. It is used to pass a non-
keyworded, variable-length argument list.
• The syntax is to use the symbol * to take in a variable number of arguments;
by convention, it is often used with the word args.
• *args allows you to handle more arguments than the number of formal
arguments that you previously defined. With *args, any number of extra
arguments can be tacked on to your current formal parameters (including zero
extra arguments).
• For example : we want to make a multiply function that takes any number of
arguments and able to multiply them all together. It can be done using *args.
• Using the *, the variable that we associate with the * becomes an iterable
meaning you can do things like iterate over it, run some higher order functions
Cntd…
• Example-1:
def myFun(*args):
for ar in args:
print (ar)
myFun('Hello', 'Welcome', 'to', 'Python Programming')

Output:
Hello
Welcome
to
Python Programming
Cntd…
• Example-2:
def myFun(arg1, *args):
print ("First argument :", arg1)
for ar in args:
print("Next argument through *args :", ar)
myFun('Hello', 'Welcome', 'to', ‘Python class’)
Output:
First argument : Hello
Next argument through *args : Welcome
Next argument through *args : to
Next argument through *args : Python class
Variable keyword arguments
• The special syntax **kwargs in function definitions in python is used to
pass a keyworded, variable-length argument list. We use the name kwargs
with the double star. The reason is, ‘**’ allows us to pass through any
number of keyword arguments.
• A keyword argument is where you provide a name to the variable as you pass
it into the function.
• One can think of the kwargs as being a dictionary that maps each keyword to
the value that we pass along side it. That is why when we iterate over the
kwargs there doesn’t seem to be any order in which they were printed out.
Cntd…
• Example:
def myFun(**kwargs):
for key,value in kwargs.items():
print (key,value)
myFun(first ='Python', mid ='for', last='developers')
Output:
first Python
mid for
last developers
Cntd…
• Example-2:
def myFun(arg1, **kwargs):
print (arg1)
for key, value in kwargs.items():
print (key, value)
myFun("Hi", first ='programmers', mid ='of', last='Python')
Output:
Hi
first programmers
mid of
last Python
Recursion
• When a function calls itself repeatedly, is called as recursion
• There are 2 components of recursion:
1) Base case: It directly specifies, result of a special case
2) Recursive (inductive) case: It calls the same function with some different value.
• Simple example of recursion is factorial numbers:
• 1 != 1  base case
• (n+1)!= (n+1) * n!  It defines all other cases except base case (recursive case)

• Remember: Each function defines a new name space, also called a scope of
function.
Factorial function: iterative vs recursive
• Iterative program: vs Recursive version:
def facto(n): def facto(n):
result=1 if n==1:
return 1
while(n>1):
else:
result= result*n return n*facto(n-1)
n=n-1 print(facto(5))
return result
print(facto(5)) Output:120

Output: 120
Fibonacci series: iterative & recursive
• Try yourself: Iterative program vs Recursive program
def fib(n): def fib(n):
i=0; j=1 if n==0 or n==1:
print(i,j,end=" ") return n
for t in range(n): else:
temp=j return fib(n-1)+fib(n-2)
j=i+j
i=temp def fib_num(n):
print(j, end=" ") for i in range(n+1):
return j print (fib(i))
fib(5) fib_num(5)
Output: 0 1 1 2 3 5 8 Output: 0 1 1 2 3 5
• H.W. : Check whether given string is palindrome or not using recursion
Global vs Local vs Nonlocal variable
• A variable declared outside of the function or in global scope is known as
global variable. Global variable can be accessed inside or outside of the
function.
• A variable declared inside the function's body or in the local scope is known
as local variable.
• Consider following examples:
1) def f():
print(s)
s="I like python"
f()
Output: I like python
Cntd…
2) def f():
s="local"
print(s)
f()
print(s)
Output: local
NameError: name 's' is not defined

3) def f():
s="local"
print(s)
s="I like python."
f()
print(s)
Output: local
Cntd…
4) def f():
print(s) # This line produce an error
s="local“
s="I like python."
f()
print(s)

• In example-4, variable ‘s’ which is inside function f() is local to that


function. But when we try to access local value of ‘s’ (using print
function), it generates an error because ‘s’ is local to f(), but value of ‘s’ is
not known at the time of accessing. Value of local ‘s’ is assigned after
print() statement using code line: s=“local”.
• To over come this issue, ‘global’ keyword is used.
global keyword
5) def f():
global s
print(s)
s="In function"
print(s)
s="In main program"
f()
print(s)

Output: In main program


In function
Cntd…
• 6) Combination of global & local keyword:
def foo(x,y):
global a
a=42
x,y=y,x
b=33
b=17
c=100
print(a,b,x,y)
a,b,x,y=1,15,3,4
foo(17,4)
print(a,b,x,y)

Output: 42 17 4 17
Nonlocal variable
• Nonlocal variable are used in nested function whose local scope is not defined. This means, the variable
can be neither in the local nor the global scope.
• 'nonlocal' keyword is used to create nonlocal variable.
Example:
def outer():
x = "local" In this code there is a nested function inner(). The inner()
def inner(): function is defined in the scope of function outer().
nonlocal x We use nonlocal keyword to create nonlocal variable. That
x = "nonlocal" means, no separate copy of ‘x’ for inner() is created, it modifies
print("inner:", x) ‘x’ of outer().
inner()
print("outer:", x) Note : If we change value of nonlocal variable, the changes
outer() appear in the local scope too.
Output:
inner: nonlocal
outer: nonlocal
lambda function
• Lambda function is a function that is defined without a name. lambda
functions are also called anonymous functions.
• While normal functions are defined using the def keyword, anonymous
functions are defined using the lambda keyword.
• A lambda function can take any number of arguments, but can only have one
expression.
• Syntax- lambda arguments: expression
• Example:
double = lambda x: x * 2
print(double(5))
Output: 10
filter() function
• The filter() function in Python takes in a function and a list as arguments.
• The function is called with all the items in the list and a new list is returned
which contains items for which the function evaluates to True.
• Example:
li=[1,2,3,4]
x=list(filter(lambda t: t%2==0,li))
print(x)
Output: [2, 4]
map() function
• The map() function in Python takes in a function and a list.
• The function is called with all the items in the list and a new list is
returned which contains items returned by that function for each item.
• Example:
li = [5, 7, 22, 97, 62]
final_list = list(map(lambda x: x*2 , li))
print(final_list)
Output: [10, 14, 44, 194, 124]
reduce() function
• The reduce() function takes a function and a list as argument.
• The function is called with a lambda function and a list. A new reduced
result is returned. It performs a repetitive operation over the pairs of the
list.
• reduce() is a part of functools module. You have to import that module to
use reduce() function.
• Example:
from functools import *
li = [5, 8, 10, 20, 50, 100]
sum = reduce((lambda x, y: x + y), li)
print (sum)
Output: 193
Function as objects
• In Python, functions are first-class objects. That means that they can
be treated like objects of any other type, e.g., int or list.
• Functions have types, e.g., the expression type(fact) has the value
<type 'function'>; they can appear in expressions, e.g., as the right-
hand side of an assignment statement or as an argument to a function;
they can be elements of lists; etc.
• Using functions as arguments can be particularly convenient in
conjunction with lists. It allows a style of coding called higher-order
programming.
• Function that take other functions as arguments are also called higher
order functions.
• Example:
def applyToEach(L, f):
"""Assumes L is a list, f a function
Mutates L by replacing each element, e, of L by f(e)"""
for i in range(len(L)): Specification (docstring)
L[i] = f(L[i])
L = [1, -2, 3.33]
print ('L =', L)
print ('Apply abs to each element of L.') Output:
applyToEach(L, abs) L = [1, -2, 3.33]
Apply abs to each element of L.
print ('L =', L) L = [1, 2, 3.33]
print('Apply int to each element of L.’) Apply int to each element of L.
applyToEach(L, int) L = [1, 2, 3]

print ('L =', L)


def facto(n):
f=1
for t in range(2,n+1):
f=f*t
return f
def applyToEach(L, f):
for i in range(len(L)):
L[i] = f (L[i])
L = [1, -2, 4.33]
print('Apply int to each element of', L)
applyToEach(L, int)
Output:
print ('L =', L) Apply int to each element of [1, -2, 4.33]
print ('Apply factorial to each element of', L) L = [1, -2, 4]
Apply factorial to each element of [1, -2, 4]
applyToEach(L, facto) L = [1, 1, 24]
Generators
• A generator is a function that returns an object (iterator) which can iterate and
return one value at a time.
• Instead of ‘return’ statement, ‘yield’ statement is used to get one value at a time
from generator function.
• Example-1:
def simpleGeneratorFun():
yield 1
yield 2
yield 3
x = simpleGeneratorFun() # x is a generator object
Output:
print(next(x)) 1
print(next(x)) 2
3
print(next(x))
Cntd…
• Example-2: Re-writing example-1
def simpleGeneratorFun():
yield 1
yield 2
yield 3
for value in simpleGeneratorFun():
print(value)
Output:
1
2
3
Generator function v/s Normal function
• Generator function contains one or more yield statement.
• When called, it returns an object (iterator) but does not start execution
immediately.
• Magic methods like __iter__() and __next__() are implemented automatically.
That means, we can iterate through items using either ‘for’ loop or next() method.
• A ‘return’ statement fully terminates function, but ‘yield’ statement pauses the
function saving all its states, then control is transferred to the caller and later
continues from that point on successive calls.
• Local variables and their states are remembered between successive calls.
• Finally, when the function terminates, StopIteration is raised automatically on
further calls.
• Example-3 : Implementation of Fibonacci series using generators
print("Using next() method:")
def fib(limit):
a, b = 0, 1
while a < limit: Output:
yield a Using next() method:
a, b = b, a + b 0
1
x = fib(5) 1
print(next(x)) 2
3
print(next(x))
Using for in loop:
print(next(x)) 0
print(next(x)) 1
1
print(next(x))
2
print("Using for in loop:") 3
for i in fib(5):
Important points for generators
• One interesting thing to note in the previous example (Fibonacci series) is that, the
value of variables a, b is remembered between each call.
• Unlike normal functions, the local variables are not destroyed when the function
yields. Furthermore, the generator object can be iterated only once.
• To restart the process we need to create another generator object using something
like: variable_name = generator_fun().
• We can use generators with ‘for’ loops directly. This is because, a ‘for’ loop takes an
iterator and iterates over it using next() function. It automatically ends when
StopIteration is raised.
• Memory efficient: To print sequence of numbers, a normal function will create the
entire sequence in memory before returning the result. This is an overkill if the
number of items in the sequence is very large.
• Generator implementation of such sequence is memory friendly and is preferred since
it only produces one item at a time.
Infinite sequence using generator
• Generators are excellent medium to represent an infinite stream of data.
Infinite streams cannot be stored in memory and since generators produce
only one item at a time, it can represent infinite stream of data.
• Following example can generate all the even numbers (at least in theory).
def all_even():
n=0
while True:
yield n
n += 2
for i in all_even():
print (i)
List Comprehension
• List comprehension provides a concise way to apply an operation to
the values in a sequence. It creates a new list in which each element is
the result of applying a given operation to a value from a sequence
(e.g., the elements in another list).
• Example:
L = [x**2 for x in range(1,7)]
print (L)
Output: [1, 4, 9, 16, 25, 36]
Cntd…
• The for clause in a list comprehension can be followed by one or more if and
for statements that are applied to the values produced by the outer for clause.
These additional clauses modify the sequence of values generated by the
first for clause and produce a new sequence of values, to which the operation
associated with the comprehension is applied.
• Example:
mixed = [1, 2, 'a', 3, 4.0]
L=[x**2 for x in mixed if type(x) == int]
print (L)
Output: [1, 4, 9]
Dictionary Comprehension
• Like List Comprehension, Python allows dictionary comprehension. We can
create dictionary using simple expressions. A dictionary comprehension
takes the form {key: value for (key, value) in iterable}
• Example:- Take two lists named keys and value and we are iterating over
them with the help of zip() function.
keys = ['a','b','c','d','e']
values = [1,2,3,4,5]
myDict = { k:v for (k,v) in zip(keys, values)}
# myDict = dict(zip(keys, values)) # We can use below too
print (myDict)
Output: {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
Cntd…
• Example-2:
myDict = {x: x**2 for x in [1,2,3,4,5]}
print (myDict)
Output:
{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
• Example-3:
newdict = {x: x**3 for x in range(10) if x**3 % 4 == 0}
print(newdict)
Output:
{0: 0, 2: 8, 4: 64, 6: 216, 8: 512}
Module
• It is possible to store parts of a program in multiple files in python.
• Python module provides us that feature.
• A module is a .py file containing Python definitions and statements.
• There are 2 types of modules in python:
1) Built-in 2) User-defined
1) Built-in module: They are predefined. We can directly use methods and
variables available in it. There are hundreds of built-in modules in python.
• Example: We have used reduce() function which is in ‘functools’ module.
Other built-in modules are- re (regular expression), numpy, sympy, scipy,
flask, Django, pandas, pyramid etc.
Cntd…
2) User-defined module: A module can define functions, classes and variables. A
module can also include runnable code. They are created by programmer to use in
other files.
• Example: Create a file called ‘circle.py’. Contents of circle.py are given below:
pi = 3.14159
def area(radius):
return pi*(radius**2)
def circumference(radius):
return 2*pi*radius
def sphereSurface(radius):
return 4*area(radius)
def sphereVolume(radius):
return (4/3)*pi*(radius**3)
Cntd…
• ‘circle.py’ becomes a module for user. Its elements like methods, variables will
be used by another file-’check.py’. Contents of ‘check.py’:
import circle
print (circle.pi)
print (circle.area(3))
print (circle.circumference(3))
print (circle.sphereSurface(3))
Note: circle.py and check.py
Output: Run ‘check.py’ file files must be in same folder,
3.14159 otherwise it produces error.
28.27431
18.849539999999998
113.09724
Cntd…
• Another way to use modules is using ‘from module_name import *’ syntax.
• Consider file named-’check1.py’. Contents of ‘check1.py’ are:
from circle import *
print (pi)
print (area(3))
print (circumference(3))
pi= 3.5
print (pi) Note: circle.py and check1.py
files must be in same folder,
Output: Run check1.py
otherwise it produces error.
3.14159
28.27431
18.849539999999998
3.5

You might also like