In [1]:
# what is a function?
# A block of code which can be called multiple times.

In [2]:
# defination of the function.
# Every function has a return value.
# Lets say,if i have no return value.. i get None.

def foo():  # function with optional parameters
    print "hello world!!"

In [3]:
print foo()


hello world!!
None

In [4]:
print foo()


hello world!!
None

In [7]:
# We get a return value for the truth of a function.
# truth of a function can be any value.
# if we dont have a return value we get None.
# return is not a print statement.
# return marks the end of the function.
def foo():  # function with optional parameters
    return "hello world!!"
    print "line1"
    print "line2"
    print "line3"

In [8]:
print foo()


hello world!!

In [12]:
## variable scope/namespace
# variables defined inside a function are available only during the function runtime.
# Literally,there is no syntax to access the variable defined inside a function.
# locals(): provides you the namespace of the local variables.

# use case I
def my_fun():
    x = 1
    print locals()
    return x

In [13]:
print my_fun()


{'x': 1}
1

In [11]:
print x


---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-11-0b640320f694> in <module>()
----> 1 print x

NameError: name 'x' is not defined

In [16]:
# use case II:
# globals -> this show your all the variables which are available globally to us.
# if i have no variable in localscope i will look into global scope.

y=10  # global variable
def my_fun():
    print locals()
    return y

In [17]:
print my_fun() # 10


{}
10

In [18]:
print y


10

In [ ]:
In [5]: globals()
Out[5]: 
{'In': ['',
  u'y = 10',
  u'def my_fun():\n    print locals()\n    return y',
  u'print my_fun()',
  u'print y',
  u'globals()'],
 'Out': {},
 '_': '',
 '__': '',
 '___': '',
 '__builtin__': <module '__builtin__' (built-in)>,
 '__builtins__': <module '__builtin__' (built-in)>,
 '__doc__': 'Automatically created module for IPython interactive environment',
 '__name__': '__main__',
 '_dh': [u'/home/khyaathi'],
 '_i': u'print y',
 '_i1': u'y = 10',
 '_i2': u'def my_fun():\n    print locals()\n    return y',
 '_i3': u'print my_fun()',
 '_i4': u'print y',
 '_i5': u'globals()',
 '_ih': ['',
  u'y = 10',
  u'def my_fun():\n    print locals()\n    return y',
  u'print my_fun()',
  u'print y',
  u'globals()'],
 '_ii': u'print my_fun()',
 '_iii': u'def my_fun():\n    print locals()\n    return y',
 '_oh': {},
 '_sh': <module 'IPython.core.shadowns' from '/usr/local/lib/python2.7/dist-packages/IPython/core/shadowns.pyc'>,
 'exit': <IPython.core.autocall.ExitAutocall at 0x7f4623d17110>,
 'get_ipython': <bound method TerminalInteractiveShell.get_ipython of <IPython.terminal.interactiveshell.TerminalInteractiveShell object at 0x7f4623cb1290>>,
 'my_fun': <function __main__.my_fun>,
 'quit': <IPython.core.autocall.ExitAutocall at 0x7f4623d17110>,
 'y': 10}

In [6]: globals()['y']
Out[6]: 10

In [7]: globals()['my_fun']
Out[7]: <function __main__.my_fun>

In [19]:
# Use case III:
# local variables are given higher precendence than global variables.

z = 10
def my_func():
    z = 11
    print locals()
    return z

In [20]:
print my_func()


{'z': 11}
11

In [21]:
print z


10

In [22]:
# use case IV:

balance = 0

def my_deposit():
    balance = balance + 5000
    return balance

In [23]:
print my_deposit()


---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
<ipython-input-23-87870cd62757> in <module>()
----> 1 print my_deposit()

<ipython-input-22-bbcc2325574c> in my_deposit()
      4 
      5 def my_deposit():
----> 6     balance = balance + 5000
      7     return balance

UnboundLocalError: local variable 'balance' referenced before assignment

In [24]:
balance = 0

def my_deposit():
    balance = 0
    balance = balance + 5000
    return balance

In [25]:
print my_deposit()


5000

In [26]:
def my_withdraw():
    balance = 0
    balance = balance - 1000
    return balance

In [27]:
print my_withdraw()


-1000

In [28]:
# global keyword

balance = 0

def my_deposit():
    global balance
    print locals()
    balance = balance + 5000
    return balance

def my_withdraw():
    global balance
    print locals()
    balance = balance - 1000
    return balance

In [29]:
print my_deposit()
print my_withdraw()


{}
5000
{}
4000

In [30]:
print balance


4000

In [31]:
# functional arguments

def my_add(a,b):
    return a + b

In [37]:
# arguments on position based.
print my_add("linux"," rocks")
print my_add(" rocks","linux")
print my_add(11,22)


linux rocks
 rockslinux
33

In [35]:
# arguments on key based.
print  my_add(a='linux',b=' rocks')
print my_add(b=' rocks',a='linux')


linux rocks
linux rocks

In [36]:
print my_add(x='linux',y='rocks')
# TODO : google task today.
# how are the agruments passed.
# 1) as references
# 2) as values


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-36-87c742088ec8> in <module>()
----> 1 print my_add(x='linux',y='rocks')

TypeError: my_add() got an unexpected keyword argument 'x'

In [38]:
# default
# default is not a keyword... you can write any variable name.
def my_multi(num,default=10):
    for value in range(1,default+1):
        print "{0:2d} * {1:2d} = {2:3d}".format(num,value,num*value)

In [40]:
my_multi(2)
my_multi(3,5)


 2 *  1 =   2
 2 *  2 =   4
 2 *  3 =   6
 2 *  4 =   8
 2 *  5 =  10
 2 *  6 =  12
 2 *  7 =  14
 2 *  8 =  16
 2 *  9 =  18
 2 * 10 =  20
 3 *  1 =   3
 3 *  2 =   6
 3 *  3 =   9
 3 *  4 =  12
 3 *  5 =  15

In [47]:
# *,**,*args,**kwargs

def my_add(a,b):
    return a + b

# *
my_value1 = [11,22]
my_value2 = [11,22,33]
print my_add(my_values)


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-47-aea2c2c1fe55> in <module>()
      7 my_value1 = [11,22]
      8 my_value2 = [11,22,33]
----> 9 print my_add(my_values)

TypeError: my_add() takes exactly 2 arguments (1 given)

In [45]:
print my_add(*my_value1)


33

In [46]:
print my_add(*my_value2)


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-46-a156508ef8dd> in <module>()
----> 1 print my_add(*my_value2)

TypeError: my_add() takes exactly 2 arguments (3 given)

In [50]:
## **

my_values = {'a':11,'b':22}
my_value2 = {'c':11,'a':11,'b':22}
print my_add(my_values)


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-50-a1cdc9c282ee> in <module>()
      3 my_values = {'a':11,'b':22}
      4 my_value2 = {'c':11,'a':11,'b':22}
----> 5 print my_add(my_values)

TypeError: my_add() takes exactly 2 arguments (1 given)

In [51]:
print my_add(**my_values)


33

In [52]:
print my_add(**my_value2)


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-52-837af9b0de72> in <module>()
----> 1 print my_add(**my_value2)

TypeError: my_add() got an unexpected keyword argument 'c'

In [ ]:
## *args

In [53]:
print help(max)


Help on built-in function max in module __builtin__:

max(...)
    max(iterable[, key=func]) -> value
    max(a, b, c, ...[, key=func]) -> value
    
    With a single iterable argument, return its largest item.
    With two or more arguments, return the largest argument.

None

In [55]:
print max(-1,-2,-3,-4,-5)
print  max(11,22)
print max(33,-1,8,100)


-1
22
100

In [56]:
# args is a tuple of values.
def gmax(*args):
    return args

In [57]:
print gmax(-1,-2,-3,-4,-5)
print  gmax(11,22)
print gmax(33,-1,8,100)


(-1, -2, -3, -4, -5)
(11, 22)
(33, -1, 8, 100)

In [60]:
def gmax(*args):
    big = -1
    for value in args:
        if value > big:
            big = value
    return big

In [61]:
print gmax(-1,-2,-3,-4,-5)
print  gmax(11,22)
print gmax(33,-1,8,100)


-1
22
100

In [62]:
# A call me app
# kwargs is a dictionary.

def callme(**kwargs):
    print kwargs

In [63]:
callme(name='kumar',loc='hyd')
callme(name='kumar',mobile='a.b.c')
callme(name='kumar',mobile='a.b.c',maiden='vijaya')


{'loc': 'hyd', 'name': 'kumar'}
{'mobile': 'a.b.c', 'name': 'kumar'}
{'mobile': 'a.b.c', 'name': 'kumar', 'maiden': 'vijaya'}

In [68]:
def callme(**kwargs):
    if 'name' in kwargs:
        print "my name is {}".format(kwargs['name'])
    if 'loc' in kwargs:
        print "my loc is {}".format(kwargs['loc'])
    if 'mobile' in kwargs:
        print "my mobile is {}".format(kwargs['mobile'])
    if 'maiden' in kwargs:
        print "my maiden in {}".format(kwargs['maiden'])

In [69]:
callme(name='kumar',loc='hyd')
callme(name='kumar',mobile='a.b.c')
callme(name='kumar',mobile='a.b.c',maiden='vijaya')


my name is kumar
my loc is hyd
my name is kumar
my mobile is a.b.c
my name is kumar
my mobile is a.b.c
my maiden in vijaya

In [ ]:
# use case:
#https://images.sftcdn.net/images/t_optimized,f_auto/p/6a5919fa-96d1-11e6-b8e8-00163ec9f5fa/1811083446/putty-screenshot.jpg
def putty(hostname,port=22):
    pass

# putty(google.com) # 22
# putty(google.com,23) # telnet

In [1]:
## Function within a function

def upper():
    y = 1
    def inner():
        return y
    return inner() # calling the inner function.

In [2]:
print upper() # 1


1

In [3]:
print inner() #1,error


---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-3-8fb235288e05> in <module>()
----> 1 print inner() #1,error

NameError: name 'inner' is not defined

In [8]:
##
def foo():
    pass

print foo
print foo()
foo


<function foo at 0x7f48a4070488>
None
Out[8]:
<function __main__.foo>

In [19]:
## function closures
# when ever i define a function(inner).. i have access to both local and global variables
# and they will be available even when i return them as address.
def upper():
    y = 1
    def inner():
        return y
    return inner

In [20]:
foo = upper()

In [21]:
print foo


<function inner at 0x7f48a40702a8>

In [22]:
print foo() #1,None,


1

In [ ]:
## functions are first class objects.
# str,int,float

In [24]:
def my_extra(my_func,x,y):
    return my_func(x,y)

def my_add(x,y):
    return x + y

def my_sub(x,y):
    if x > y:
        return x - y
    else:
        return y - x

In [25]:
print my_extra(my_add,11,12)
print my_extra(my_sub,32,23)


23
9

In [26]:
# map,filter and lambda

print help(map)


Help on built-in function map in module __builtin__:

map(...)
    map(function, sequence[, sequence, ...]) -> list
    
    Return a list of the results of applying the function to the items of
    the argument sequence(s).  If more than one sequence is given, the
    function is called with an argument list consisting of the corresponding
    item of each sequence, substituting None for missing values when not all
    sequences have the same length.  If the function is None, return a list of
    the items of the sequence (or a list of tuples if more than one sequence).

None

In [27]:
def my_square(a):
    return a * a

In [29]:
print my_square(2)
print my_square(25)


4
625

In [31]:
print map(my_square,[2,44,55,66,77,88])


[4, 1936, 3025, 4356, 5929, 7744]

In [32]:
## filter
print help(filter)


Help on built-in function filter in module __builtin__:

filter(...)
    filter(function or None, sequence) -> list, tuple, or string
    
    Return those items of sequence for which function(item) is true.  If
    function is None, return the items that are true.  If sequence is a tuple
    or string, return the same type, else return a list.

None

In [33]:
def even(a):
    if a % 2 == 0:
        return 'even'

In [34]:
print even(2)
print even(3)


even
None

In [35]:
print filter(even,range(1,11))


[2, 4, 6, 8, 10]

In [38]:
# lambda - creating function on fly.
print map(my_square,[2,44,55,66,77,88])
print map(lambda a:a*a,[2,44,55,66,77,88])
print filter(my_square,[2,44,55,66,77,88])


[4, 1936, 3025, 4356, 5929, 7744]
[4, 1936, 3025, 4356, 5929, 7744]
[2, 44, 55, 66, 77, 88]

In [39]:
print filter(even,range(1,11))
print filter(lambda a:a%2==0,range(1,11))
print map(even,range(1,11))


[2, 4, 6, 8, 10]
[2, 4, 6, 8, 10]
[None, 'even', None, 'even', None, 'even', None, 'even', None, 'even']

In [ ]: