Chapter 5 Library and Functions

Library are group of functions

5.1 Importing Library

There are two methods to import library functions:

5.1.1 Standalone Namespace

# access function through: libName.functionName
- import <libName>                        

# access function through: shortName.functionName
- import <libName> as <shortName>         

Use as for aliasing library name. This is useful if you have conflicting library name

import math
math.sqrt(9)

import math as m   ## use library shortname
m.sqrt(9)
## 3.0
## 3.0

5.1.2 Global Namespace

# all functions available at global namespace
- from   <libName> import *

# access function through original names
- from   <libName> import <functionName>      

# access function through custom names
- from   <libName> import <functionName> as <shortFunctionName>  
from math import sqrt
sqrt(9)

from math import sqrt as sq
sq(9)
## 3.0
## 3.0

5.2 Functions

5.2.1 Define

By default, arguments are assigned to function left to right. However, you can also specify the argument assignment during function call. Function can have default args value.

def myfun(x,y=3):
    print ('x:',x)
    print ('y:',y)

myfun(5,8)      ## default function read args from left to right
myfun (y=8,x=5) ## but we can specific as well
myfun (x=5)     ## args x not specified, function assume default=
## x: 5
## y: 8
## x: 5
## y: 8
## x: 5
## y: 3

5.2.2 List Within Function

Consider a function is an object, its variable (some_list) is a reference. Hence its value is remembered when no parameter is passed over. it is counter intuitive, always ensure to pass the arguments to function, even though it is a an empty list.

def spam (elem, some_list=[]):
    some_list.append(elem)
    return some_list

print (spam(1))
print (spam(2,[6]))
print (spam(3))
print (spam(2,[7]))
print (spam(4, []))
## [1]
## [6, 2]
## [1, 3]
## [7, 2]
## [4]

5.2.3 Return Statement

Multiple value is returned as tuple. Use multiple assignment to assign to multiple variable

def bigger(x,y):
    if (x>y):
        return x
    else:
        return y

def minmax(x,y,z):
    return min(x,y,z), max(x,y,z)

big   = bigger(5,8)
a,b   = minmax(7,8,9)     # multiple assignment
c     = minmax(7,8,9)     # tuple

print (big)  ## noolean
print (a,b)  ## integer
print (c)    ## tuple
## 8
## 7 9
## (7, 9)

if no return statement, python return None

def dummy():
    print ('This is a dummy function, return no value')

dummy() == None
## This is a dummy function, return no value
## True

5.2.4 Argument

Passing too many arguments will result in an error. Passing too little arguments without default value defined will also result in error. For dynamic number of arguments, see args in the next section.

def myfun(x,y):
    print (x)
    print (y)

myfun(1,2,3,4,5)
myfun(1)
## Error in py_call_impl(callable, dots$args, dots$keywords): TypeError: myfun() takes 2 positional arguments but 5 were given
## Error in py_call_impl(callable, dots$args, dots$keywords): TypeError: myfun() missing 1 required positional argument: 'y'

Function as Argument

def myfun(x,y,f):
    f(x,y)

myfun('hello',54,print)
## hello 54

Breaking Dict as Argument

Below example break dict to a function. However, be careful not to pass extra key to the function, which will result in error.

def foo(a,b,c,d=1):
    print(a, b, c, d)

foo(**{"a":2,"b":3,"c":4})          ## ok
foo(**{"a":2,"b":3,"c":4, "z":100}) ## Error, 'z' not recognized
## 2 3 4 1
## Error in py_call_impl(callable, dots$args, dots$keywords): TypeError: foo() got an unexpected keyword argument 'z'

5.2.5 Argument: args

All dynamic length of argumens not captured in the defined argument will overflow into args, which is a tuple.

Example 1 - All tails overflow to args

First argument goes to x, second argument goes to y, remaining overflow to args.

def myfun(x,y,*args):
    print (x)
    print (y)
    print (args)     #tuple
    
myfun(1,2,3,4,5,'any')
## 1
## 2
## (3, 4, 5, 'any')

Example 2 - Middle overflow to args

def myfun(x,*args, y=9):
    print (x)
    print (y)
    print (args)     #tuple
    
myfun(1,2,3,4,5)
## 1
## 9
## (2, 3, 4, 5)

Example 3 - All goes to args

def myfun(*args):
    print (args)     #tuple
    
myfun(1,2,3,4,5)
## (1, 2, 3, 4, 5)

Example 4 - Empty args

def myfun(x,y,*args):
    print (x)
    print (y)
    print (args)
    
myfun(1,2)
## 1
## 2
## ()

5.2.6 Argument: kwargs

kwargs is a dictionary

Example 1 - All goes into kwargs

def foo(**kwargs):
    print(kwargs)
    
foo(a=1,b=2,c=3)
## {'a': 1, 'b': 2, 'c': 3}

Example 2 - Tails overflow to kwargs

First param goes to x, the rest goes to kwargs.

def foo(x,**kwargs):
    print(x)
    print(kwargs)
    
foo(9,a=1,b=2,c=3)
foo(9)              ## empty kwargs dictionary
## 9
## {'a': 1, 'b': 2, 'c': 3}
## 9
## {}

Mixing args, kwargs

Always put args before kwargs, otherwise there will be an Error.

def foo(x,y=2,*args,**kwargs):
    print (x,y, args, kwargs)
    
foo(1,2,3,4,5,c=6,d=7)  ## ok
foo(1,2,3,c=6,4,5,d=7)  ## ERROR, always puts args before kwargs
## positional argument follows keyword argument (<string>, line 5)