Programming for Data Science¶

Functions¶

Dr. Bhargavi R

SCOPE, VIT Chennai

Introduction¶

  • Any practical/ real time application consists of thousands of lines of code.
  • A single program for the complete application has several practical issues like
  • Readability
  • Understandability
  • Code repetition
  • Too many variables
  • Implementation issues
  • Collaborative working
  • In this session, we will learn how to handle complex/bigger application.
  • Achieved by breaking down the bigger problem into smaller sub tasks.
  • Smaller programs are easy to understand.
  • Can be reused which inturn reduces the length of the code by avoiding rewriting the same code.

Function(s)¶

  • A function is a named (need not be!, as we will see) group of instructions performing some task.
  • When the program execution reaches a function call, execute the group of instructions under that function.
  • When task is over, come back to where the function is called.
  • Built in Functions: print(), input(), len() etc,.
  • To be precise, Don't Repeat Yourself! (DRY Principle)
  • Python functions are first class - means functions are treated like any other variables.
    • A function can be passed as an argument to other functions
    • Can be returned by another function
    • Can be assigned as a value to a variable

Built-in Functions¶

  • Python has a number of built-in functions
  • Ex : print(), min(), max(), len(), type() etc.
In [1]:
# Find the element with smallest value in a list

my_list = [78, 45, 34, 25, 68, 84]
my_min = min(my_list)
print(f'min value is {my_min}')
# help(min)
min value is 25
In [2]:
# min from integers
print(min(10, 23, 5, 56))

# min from strings
print(min('AbC', 'abc', 'ABC',  'BCD'))
5
ABC

Python Modules¶

math¶

In [3]:
# Python code to demonstrate  sqrt(), pow() ceil(), trunc() and floor() functions
# To demonstarte this example we need to import math library of python
# First, let's import math library using import

import math

p = math.pi
print(p)
print('Value of p is {0: 0.2f}'.format(p))
3.141592653589793
Value of p is  3.14
In [4]:
help(math)
Help on module math:

NAME
    math

MODULE REFERENCE
    https://docs.python.org/3.10/library/math.html
    
    The following documentation is automatically generated from the Python
    source files.  It may be incomplete, incorrect or include features that
    are considered implementation detail and may vary between Python
    implementations.  When in doubt, consult the module reference at the
    location listed above.

DESCRIPTION
    This module provides access to the mathematical functions
    defined by the C standard.

FUNCTIONS
    acos(x, /)
        Return the arc cosine (measured in radians) of x.
        
        The result is between 0 and pi.
    
    acosh(x, /)
        Return the inverse hyperbolic cosine of x.
    
    asin(x, /)
        Return the arc sine (measured in radians) of x.
        
        The result is between -pi/2 and pi/2.
    
    asinh(x, /)
        Return the inverse hyperbolic sine of x.
    
    atan(x, /)
        Return the arc tangent (measured in radians) of x.
        
        The result is between -pi/2 and pi/2.
    
    atan2(y, x, /)
        Return the arc tangent (measured in radians) of y/x.
        
        Unlike atan(y/x), the signs of both x and y are considered.
    
    atanh(x, /)
        Return the inverse hyperbolic tangent of x.
    
    ceil(x, /)
        Return the ceiling of x as an Integral.
        
        This is the smallest integer >= x.
    
    comb(n, k, /)
        Number of ways to choose k items from n items without repetition and without order.
        
        Evaluates to n! / (k! * (n - k)!) when k <= n and evaluates
        to zero when k > n.
        
        Also called the binomial coefficient because it is equivalent
        to the coefficient of k-th term in polynomial expansion of the
        expression (1 + x)**n.
        
        Raises TypeError if either of the arguments are not integers.
        Raises ValueError if either of the arguments are negative.
    
    copysign(x, y, /)
        Return a float with the magnitude (absolute value) of x but the sign of y.
        
        On platforms that support signed zeros, copysign(1.0, -0.0)
        returns -1.0.
    
    cos(x, /)
        Return the cosine of x (measured in radians).
    
    cosh(x, /)
        Return the hyperbolic cosine of x.
    
    degrees(x, /)
        Convert angle x from radians to degrees.
    
    dist(p, q, /)
        Return the Euclidean distance between two points p and q.
        
        The points should be specified as sequences (or iterables) of
        coordinates.  Both inputs must have the same dimension.
        
        Roughly equivalent to:
            sqrt(sum((px - qx) ** 2.0 for px, qx in zip(p, q)))
    
    erf(x, /)
        Error function at x.
    
    erfc(x, /)
        Complementary error function at x.
    
    exp(x, /)
        Return e raised to the power of x.
    
    expm1(x, /)
        Return exp(x)-1.
        
        This function avoids the loss of precision involved in the direct evaluation of exp(x)-1 for small x.
    
    fabs(x, /)
        Return the absolute value of the float x.
    
    factorial(x, /)
        Find x!.
        
        Raise a ValueError if x is negative or non-integral.
    
    floor(x, /)
        Return the floor of x as an Integral.
        
        This is the largest integer <= x.
    
    fmod(x, y, /)
        Return fmod(x, y), according to platform C.
        
        x % y may differ.
    
    frexp(x, /)
        Return the mantissa and exponent of x, as pair (m, e).
        
        m is a float and e is an int, such that x = m * 2.**e.
        If x is 0, m and e are both 0.  Else 0.5 <= abs(m) < 1.0.
    
    fsum(seq, /)
        Return an accurate floating point sum of values in the iterable seq.
        
        Assumes IEEE-754 floating point arithmetic.
    
    gamma(x, /)
        Gamma function at x.
    
    gcd(*integers)
        Greatest Common Divisor.
    
    hypot(...)
        hypot(*coordinates) -> value
        
        Multidimensional Euclidean distance from the origin to a point.
        
        Roughly equivalent to:
            sqrt(sum(x**2 for x in coordinates))
        
        For a two dimensional point (x, y), gives the hypotenuse
        using the Pythagorean theorem:  sqrt(x*x + y*y).
        
        For example, the hypotenuse of a 3/4/5 right triangle is:
        
            >>> hypot(3.0, 4.0)
            5.0
    
    isclose(a, b, *, rel_tol=1e-09, abs_tol=0.0)
        Determine whether two floating point numbers are close in value.
        
          rel_tol
            maximum difference for being considered "close", relative to the
            magnitude of the input values
          abs_tol
            maximum difference for being considered "close", regardless of the
            magnitude of the input values
        
        Return True if a is close in value to b, and False otherwise.
        
        For the values to be considered close, the difference between them
        must be smaller than at least one of the tolerances.
        
        -inf, inf and NaN behave similarly to the IEEE 754 Standard.  That
        is, NaN is not close to anything, even itself.  inf and -inf are
        only close to themselves.
    
    isfinite(x, /)
        Return True if x is neither an infinity nor a NaN, and False otherwise.
    
    isinf(x, /)
        Return True if x is a positive or negative infinity, and False otherwise.
    
    isnan(x, /)
        Return True if x is a NaN (not a number), and False otherwise.
    
    isqrt(n, /)
        Return the integer part of the square root of the input.
    
    lcm(*integers)
        Least Common Multiple.
    
    ldexp(x, i, /)
        Return x * (2**i).
        
        This is essentially the inverse of frexp().
    
    lgamma(x, /)
        Natural logarithm of absolute value of Gamma function at x.
    
    log(...)
        log(x, [base=math.e])
        Return the logarithm of x to the given base.
        
        If the base not specified, returns the natural logarithm (base e) of x.
    
    log10(x, /)
        Return the base 10 logarithm of x.
    
    log1p(x, /)
        Return the natural logarithm of 1+x (base e).
        
        The result is computed in a way which is accurate for x near zero.
    
    log2(x, /)
        Return the base 2 logarithm of x.
    
    modf(x, /)
        Return the fractional and integer parts of x.
        
        Both results carry the sign of x and are floats.
    
    nextafter(x, y, /)
        Return the next floating-point value after x towards y.
    
    perm(n, k=None, /)
        Number of ways to choose k items from n items without repetition and with order.
        
        Evaluates to n! / (n - k)! when k <= n and evaluates
        to zero when k > n.
        
        If k is not specified or is None, then k defaults to n
        and the function returns n!.
        
        Raises TypeError if either of the arguments are not integers.
        Raises ValueError if either of the arguments are negative.
    
    pow(x, y, /)
        Return x**y (x to the power of y).
    
    prod(iterable, /, *, start=1)
        Calculate the product of all the elements in the input iterable.
        
        The default start value for the product is 1.
        
        When the iterable is empty, return the start value.  This function is
        intended specifically for use with numeric values and may reject
        non-numeric types.
    
    radians(x, /)
        Convert angle x from degrees to radians.
    
    remainder(x, y, /)
        Difference between x and the closest integer multiple of y.
        
        Return x - n*y where n*y is the closest integer multiple of y.
        In the case where x is exactly halfway between two multiples of
        y, the nearest even value of n is used. The result is always exact.
    
    sin(x, /)
        Return the sine of x (measured in radians).
    
    sinh(x, /)
        Return the hyperbolic sine of x.
    
    sqrt(x, /)
        Return the square root of x.
    
    tan(x, /)
        Return the tangent of x (measured in radians).
    
    tanh(x, /)
        Return the hyperbolic tangent of x.
    
    trunc(x, /)
        Truncates the Real x to the nearest Integral toward 0.
        
        Uses the __trunc__ magic method.
    
    ulp(x, /)
        Return the value of the least significant bit of the float x.

DATA
    e = 2.718281828459045
    inf = inf
    nan = nan
    pi = 3.141592653589793
    tau = 6.283185307179586

FILE
    /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/lib-dynload/math.cpython-310-darwin.so


In [5]:
def my_sqrt( n ):
    return math.sqrt(n)
In [6]:
number = int(input("Enter a number "))
print(f'sqrt of {number} is { my_sqrt(number)}')
Enter a number 15
sqrt of 15 is 3.872983346207417
In [7]:
print(f'ceil(pi) is {math.ceil(p)}')
print(f'floor(pi) is {math.floor(p)}')
print(f'trunc(pi) is {math.trunc(p)}')
print(f'8 power 2 is {math.pow(8, 2)}')
ceil(pi) is 4
floor(pi) is 3
trunc(pi) is 3
8 power 2 is 64.0

random module¶

In [8]:
import random
print( dir(random) )
['BPF', 'LOG4', 'NV_MAGICCONST', 'RECIP_BPF', 'Random', 'SG_MAGICCONST', 'SystemRandom', 'TWOPI', '_ONE', '_Sequence', '_Set', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_accumulate', '_acos', '_bisect', '_ceil', '_cos', '_e', '_exp', '_floor', '_index', '_inst', '_isfinite', '_log', '_os', '_pi', '_random', '_repeat', '_sha512', '_sin', '_sqrt', '_test', '_test_generator', '_urandom', '_warn', 'betavariate', 'choice', 'choices', 'expovariate', 'gammavariate', 'gauss', 'getrandbits', 'getstate', 'lognormvariate', 'normalvariate', 'paretovariate', 'randbytes', 'randint', 'random', 'randrange', 'sample', 'seed', 'setstate', 'shuffle', 'triangular', 'uniform', 'vonmisesvariate', 'weibullvariate']
In [9]:
# Generate a random number

x = random.random() # Return a random floating point number in the range [0.0, 1.0)
print('Random number generated is', x)
Random number generated is 0.7987523391787701
In [10]:
x = random.randint(15, 25) # Return a random intger in the range [15, 25)
print('Random number generated is', x)
Random number generated is 17
In [11]:
x = random.choice([3, 5, 7,9]) # Return a random element from the non-empty sequence 
print(x)

print(random.choice(['Christina', 'Gourav','Namitha','Udbhav']))
9
Christina

User Defined Functions¶

Defining a Function¶

def function_name(arg1, arg2,.., argn):
        stmt1
        stmt2
        return val

Invoking a Function¶

var1 = function_name(par1, par2,.., parn)
    function_name(par1, par2,.., parn)
In [12]:
# Defining a function that simply prints the message

def my_print(msg):
    print(msg)
In [13]:
# Calling my_print
text = 'My Message'
my_print(text)
my_print('Second Message')
my_print(234)
My Message
Second Message
234
In [14]:
# Define a function that can perform the addition of two arguments

def my_add (arg1, arg2):
    '''Return the sum of two numbers
    input - Two operands
    Author - Bhargavi
    '''
    result = arg1 + arg2
    return result
In [15]:
help(my_add)
Help on function my_add in module __main__:

my_add(arg1, arg2)
    Return the sum of two numbers
    input - Two operands
    Author - Bhargavi

In [16]:
# Call my_add

int_sum = my_add(10, 22)
print(int_sum)
32
In [17]:
# Call my_add

print(my_add(12.5, 1.2))
13.7
In [18]:
# Call my_add

print(my_add('Python', ' Function'))
Python Function

Keyword Arguments¶

  • The functions we have looked at so far were called with a fixed number of positional arguments.
  • A positional argument is an argument that is assigned to a particular parameter based on its position in the argument list.
  • For example:

image.png

  • A keyword argument is an argument that is specified by parameter name, rather than as a positional argument as shown below image.png
In [19]:
def my_function(a, b, c):
    print(a, b, c)

my_function(10,20,30)
10 20 30
In [20]:
my_function(c= 2, a = 5, b = 23)
5 23 2
In [21]:
my_function(4, 2, c=8)
4 2 8
In [22]:
my_function(a = 4, 2, 8) # Does this work?
  Input In [22]
    my_function(a = 4, 2, 8) # Does this work?
                           ^
SyntaxError: positional argument follows keyword argument

Default Arguments¶

  • A default argument is an argument that can be optionally provided when the function is called. image.png
  • In this example, the argument 'term' is optional.
  • If the value is not passed then the default value 20 is used inside the function.
  • Else any other value can be passed as term argument which will replace the default value
In [23]:
def my_function( a , b=20, c=10):
    print(a, b, c)
In [24]:
my_function(13)
13 20 10
In [25]:
my_function(22, c=134)
22 20 134

Arbitrary Arguments¶

  • What if you don't know how many arguments are needed while defining function?
  • A trivial example is, a max function can take 2 or more inputs.
  • How can we specify it while defining a function?
In [26]:
#A trivial example

def max_(*args):
    return max(args)
In [27]:
max_(1)
Out[27]:
1
In [28]:
max_(1, 2)
Out[28]:
2
In [29]:
max_(5, 4, 3, 2, 1, 9)
Out[29]:
9
In [30]:
def arbit_function(*args):
    print(args)
In [31]:
arbit_function(2)
(2,)
In [32]:
arbit_function(3,5,7)
(3, 5, 7)
  • What if you want to support arbitrary arguments as named arguments func(a=5, b=3, many to come)?
In [33]:
def arbit_function(**kwargs):
    print(kwargs)
In [34]:
arbit_function(x=10, y = 20, z = 30)
{'x': 10, 'y': 20, 'z': 30}
In [35]:
arbit_function(x=10, y = 20, z = 30, p = 50)
{'x': 10, 'y': 20, 'z': 30, 'p': 50}

Python functions are 1$^{st}$ class¶

  • We have already mentioned that Python functions are first class.
  • Can be treated like any other variable.
  • Can be passed as an argument to other functions.
  • Can be returned by another function.
  • Can be assigned as a value to a variable.
  • Let's now see few example demonstrating this.
  • def is a true executable statement
  • So def can appear anywhere in the code
In [37]:
# Let's define a function called my_concate(s1,s2) which concatenates s1 and s2
# which takes two forms 

test = (int)(input("Enter 1 or 0"))
print(test)

if(test == 1):
    def my_concate(s1,s2):
        return s1+s2
else:
    def my_concate(s1,s2):
        return s2 + s1

x = 'AB'
y = 'CD'

print(my_concate( x, y))
Enter 1 or 01
1
ABCD
In [38]:
# Let's see another example which demonstrates the first class type function

def f1():
    print('In function 1')
def f2():
    print('In function 2')
def f3():
    print('In function 3')
In [39]:
x = input('Enter 1 or 2 or 3')

if (x == '1'):
    my_function = f1
elif(x == '2'):
    my_function = f2
elif( x == '3'):
    my_function = f3

my_function()
Enter 1 or 2 or 33
In function 3

Scope of variables¶

  • Variables that are assigned in a called function are said to exist in that function’s local scope.
  • Variables that are assigned outside all functions are said to exist in the global scope.
  • A variable is called Local variable, if it exists in local scope.
  • A variable is called Global variable, if it exists in gloal scope.

Name Resolution: The LEGB Rule¶

image.png

Local variables - first¶

In [40]:
a   = 10       # This variable is in global scope

def my_funct(b):
    a = 30
    c = a + b  # C is in local scope
    return c

val = 20
print(my_funct(val))
print(a)
50
10
In [41]:
a   = 10       # This variable is in global scope

def my_funct(b):
    c = a + b  # C is in local scope
    return c

val = 20
my_funct(val)
Out[41]:
30
In [42]:
# import the user defined module my_calc

import my_calc

x = 40
y = my_calc.fah_cel(x)
print(y)
4.444444444444445

lambda¶

  • We can define anonymous function using lambda
  • lambda function can take any number of arguments, but can only have one expression
  • lambda function is defined as follows:
    lambda arguments: expression
      `
    
In [43]:
caps = lambda my_string : my_string.upper()
str1 = 'python'
result = caps(str1.strip())
print(result)
print((lambda my_string : my_string.lower())('BHARGAVI'))
PYTHON
bhargavi
In [44]:
# We will now see see power of lambda
def raiseToX(n):
    return (lambda a, b : (a + b) ** n)

raiseTo2 = raiseToX(2)
raiseTo3 = raiseToX(3)
x = 1
y = 2
print(raiseTo2(x, y), raiseTo3(x, y))
9 27

map()¶

  • `map()' function applies a function to every element of a list and returns the resultant list
In [45]:
def funct1(element):
    return ('even'  if element % 2 == 0  else 'odd')

list1 = list(range(1,10,1))
result = map(funct1, list1)

for ele in result:
    print(ele)
odd
even
odd
even
odd
even
odd
even
odd
In [46]:
list1 = [i for i in range(0,6)] # List comprehension 
result = map(lambda x: x * x, list1)
print(list(result))
[0, 1, 4, 9, 16, 25]