+
+
+
+
+
+<html><body><document><title>Functional Approach</title><paragraph>Functions allow us to enclose a set of statements and call the function again
+and again instead of repeating the group of statements everytime. Functions also
+allow us to isolate a piece of code from all the other code and provides the
+convenience of not polluting the global variables.</paragraph><paragraph>Function in python is defined with the keyword <strong>def</strong> followed by the name
+of the function, in turn followed by a pair of parenthesis which encloses the
+list of parameters to the function. The definition line ends with a ':'. The
+definition line is followed by the body of the function intended by one block.
+The Function must return a value:</paragraph><literal_block>def factorial(n):
+ fact = 1
+ for i in range(2, n):
+ fact *= i
+
+ return fact</literal_block><paragraph>The code snippet above defines a function with the name factorial, takes the
+number for which the factorial must be computed, computes the factorial and
+returns the value.</paragraph><paragraph>A Function once defined can be used or called anywhere else in the program. We
+call a fucntion with its name followed by a pair of parenthesis which encloses
+the arguments to the function.</paragraph><paragraph>The value that function returns can be assigned to a variable. Let's call the
+above function and store the factorial in a variable:</paragraph><literal_block>fact5 = factorial(5)</literal_block><paragraph>The value of fact5 will now be 120, which is the factorial of 5. Note that we
+passed 5 as the argument to the function.</paragraph><paragraph>It may be necessary to document what the function does, for each of the function
+to help the person who reads our code to understand it better. In order to do
+this Python allows the first line of the function body to be a string. This
+string is called as Documentation String or docstring. docstrings prove
+to be very handy since there are number of tools which can pull out all the
+docstrings from Python functions and generate the documentation automatically
+from it. docstrings for functions can be written as follows:</paragraph><literal_block>def factorial(n):
+ 'Returns the factorial for the number n.'
+ fact = 1
+ for i in range(2, n):
+ fact *= i
+
+ return fact</literal_block><paragraph>An important point to note at this point is that, a function can return any
+Python value or a Python object, which also includes a Tuple. A Tuple is
+just a collection of values and those values themselves can be of any other
+valid Python datatypes, including Lists, Tuples, Dictionaries among other
+things. So effectively, if a function can return a tuple, it can return any
+number of values through a tuple</paragraph><paragraph>Let us write a small function to swap two values:</paragraph><literal_block>def swap(a, b):
+ return b, a
+
+c, d = swap(a, b)</literal_block>
+
+1. Function scope
+<paragraph>The variables used inside the function are confined to the function's scope
+and doesn't pollute the variables of the same name outside the scope of the
+function. Also the arguments passed to the function are passed by-value if
+it is of basic Python data type:</paragraph><literal_block>def cant_change(n):
+ n = 10
+
+n = 5
+cant_change(n)</literal_block><paragraph>Upon running this code, what do you think would have happened to value of n
+which was assigned 5 before the function call? If you have already tried out
+that snippet on the interpreter you already know that the value of n is not
+changed. This is true of any immutable types of Python like Numbers, Strings
+and Tuples. But when you pass mutable objects like Lists and Dictionaries
+the values are manipulated even outside the function:</paragraph><literal_block>>>> def can_change(n):
+... n[1] = James
+...
+
+>>> name = ['Mr.', 'Steve', 'Gosling']
+>>> can_change(name)
+>>> name
+['Mr.', 'James', 'Gosling']</literal_block><paragraph>If nothing is returned by the function explicitly, Python takes care to return
+None when the funnction is called.</paragraph>
+
+
+
+2. Default Arguments
+<paragraph>There may be situations where we need to allow the functions to take the
+arguments optionally. Python allows us to define function this way by providing
+a facility called Default Arguments. For example, we need to write a function
+that returns a list of fibonacci numbers. Since our function cannot generate an
+infinite list of fibonacci numbers, we need to specify the number of elements
+that the fibonacci sequence must contain. Suppose, additionally, we want to the
+function to return 10 numbers in the sequence if no option is specified we can
+define the function as follows:</paragraph><literal_block>def fib(n=10):
+ fib_list = [0, 1]
+ for i in range(n - 2):
+ next = fib_list[-2] + fib_list[-1]
+ fib_list.append(next)
+ return fib_list</literal_block><paragraph>When we call this function, we can optionally specify the value for the
+parameter n, during the call as an argument. Calling with no argument and
+argument with n=5 returns the following fibonacci sequences:</paragraph><literal_block>fib()
+[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
+fib(5)
+[0, 1, 1, 2, 3]</literal_block>
+
+
+
+3. Keyword Arguments
+<paragraph>When a function takes a large number of arguments, it may be difficult to
+remember the order of the parameters in the function definition or it may
+be necessary to pass values to only certain parameters since others take
+the default value. In either of these cases, Python provides the facility
+of passing arguments by specifying the name of the parameter as defined in
+the function definition. This is known as Keyword Arguments.</paragraph><paragraph>In a function call, Keyword arguments can be used for each argument, in the
+following fashion:</paragraph><literal_block>argument_name=argument_value
+Also denoted as: keyword=argument
+
+def wish(name='World', greetings='Hello'):
+ print "%s, %s!" % (greetings, name)</literal_block><paragraph>This function can be called in one of the following ways. It is important to
+note that no restriction is imposed in the order in which Keyword arguments
+can be specified. Also note, that we have combined Keyword arguments with
+Default arguments in this example, however it is not necessary:</paragraph><literal_block>wish(name='Guido', greetings='Hey')
+wish(greetings='Hey', name='Guido')</literal_block><paragraph>Calling functions by specifying arguments in the order of parameters specified
+in the function definition is called as Positional arguments, as opposed to
+Keyword arguments. It is possible to use both Positional arguments and
+Keyword arguments in a single function call. But Python doesn't allow us to
+bungle up both of them. The arguments to the function, in the call, must always
+start with Positional arguments which is in turn followed by Keyword
+arguments:</paragraph><literal_block>def my_func(x, y, z, u, v, w):
+ # initialize variables.
+ ...
+ # do some stuff
+ ...
+ # return the value</literal_block><paragraph>It is valid to call the above functions in the following ways:</paragraph><literal_block>my_func(10, 20, 30, u=1.0, v=2.0, w=3.0)
+my_func(10, 20, 30, 1.0, 2.0, w=3.0)
+my_func(10, 20, z=30, u=1.0, v=2.0, w=3.0)
+my_func(x=10, y=20, z=30, u=1.0, v=2.0, w=3.0)</literal_block><paragraph>Following lists some of the invalid calls:</paragraph><literal_block>my_func(10, 20, z=30, 1.0, 2.0, 3.0)
+my_func(x=10, 20, z=30, 1.0, 2.0, 3.0)
+my_func(x=10, y=20, z=30, u=1.0, v=2.0, 3.0)</literal_block>
+
+
+
+4. Parameter Packing and Unpacking
+<paragraph>The positional arguments passed to a function can be collected in a tuple
+parameter and keyword arguments can be collected in a dictionary. Since keyword
+arguments must always be the last set of arguments passed to a function, the
+keyword dictionary parameter must be the last parameter. The function definition
+must include a list explicit parameters, followed by tuple paramter collecting
+parameter, whose name is preceded by a <strong>*</strong>, for collecting positional
+parameters, in turn followed by the dictionary collecting parameter, whose name
+is preceded by a <strong>**</strong></paragraph><literal_block>def print_report(title, *args, **name):
+ """Structure of *args*
+ (age, email-id)
+ Structure of *name*
+ {
+ 'first': First Name
+ 'middle': Middle Name
+ 'last': Last Name
+ }
+ """
+
+ print "Title: %s" % (title)
+ print "Full name: %(first)s %(middle)s %(last)s" % name
+ print "Age: %d\nEmail-ID: %s" % args</literal_block><paragraph>The above function can be called as. Note, the order of keyword parameters can
+be interchanged:</paragraph><literal_block>>>> print_report('Employee Report', 29, 'johny@example.com', first='Johny',
+ last='Charles', middle='Douglas')
+Title: Employee Report
+Full name: Johny Douglas Charles
+Age: 29
+Email-ID: johny@example.com</literal_block><paragraph>The reverse of this can also be achieved by using a very identical syntax while
+calling the function. A tuple or a dictionary can be passed as arguments in
+place of a list of Positional arguments or Keyword arguments respectively
+using <strong>*</strong> or <strong>**</strong></paragraph><literal_block>def print_report(title, age, email, first, middle, last):
+ print "Title: %s" % (title)
+ print "Full name: %s %s %s" % (first, middle, last)
+ print "Age: %d\nEmail-ID: %s" % (age, email)
+
+>>> args = (29, 'johny@example.com')
+>>> name = {
+ 'first': 'Johny',
+ 'middle': 'Charles',
+ 'last': 'Douglas'
+ }
+>>> print_report('Employee Report', *args, **name)
+Title: Employee Report
+Full name: Johny Charles Douglas
+Age: 29
+Email-ID: johny@example.com</literal_block>
+
+
+
+5. Nested Functions and Scopes
+<paragraph>Python allows nesting one function inside another. This style of programming
+turns out to be extremely flexible and powerful features when we use Python
+decorators. We will not talk about decorators is beyond the scope of this
+course. If you are interested in knowing more about decorator programming in
+Python you are suggested to read:</paragraph><line_block><line>
</line></line_block><paragraph>However, the following is an example for nested functions in Python:</paragraph><literal_block>def outer():
+ print "Outer..."
+ def inner():
+ print "Inner..."
+ print "Outer..."
+ inner()
+
+>>> outer()</literal_block>
+
+
+
+6. map, reduce and filter functions
+<paragraph>Python provides several built-in functions for convenience. The <strong>map()</strong>,
+<strong>reduce()</strong> and <strong>filter()</strong> functions prove to be very useful with sequences like
+Lists.</paragraph><paragraph>The <strong>map</strong> (function, sequence) function takes two arguments: function
+and a sequence argument. The function argument must be the name of the
+function which in turn takes a single argument, the individual element of the
+sequence. The <strong>map</strong> function calls function(item), for each item in the
+sequence and returns a list of values, where each value is the value returned
+by each call to function(item). <strong>map()</strong> function allows to pass more than
+one sequence. In this case, the first argument, function must take as many
+arguments as the number of sequences passed. This function is called with each
+corresponding element in the each of the sequences, or <strong>None</strong> if one of the
+sequence is exhausted:</paragraph><literal_block>def square(x):
+ return x*x
+
+>>> map(square, [1, 2, 3, 4])
+[1, 4, 9, 16]
+
+def mul(x, y):
+ return x*y
+
+>>> map(mul, [1, 2, 3, 4], [6, 7, 8, 9])</literal_block><paragraph>The <strong>filter</strong> (function, sequence) function takes two arguments, similar to
+the <strong>map()</strong> function. The <strong>filter</strong> function calls function(item), for each
+item in the sequence and returns all the elements in the sequence for which
+function(item) returned True:</paragraph><literal_block>def even(x):
+ if x % 2:
+ return True
+ else:
+ return False
+
+>>> filter(even, range(1, 10))
+[1, 3, 5, 7, 9]</literal_block><paragraph>The <strong>reduce</strong> (function, sequence) function takes two arguments, similar to
+<strong>map</strong> function, however multiple sequences are not allowed. The <strong>reduce</strong>
+function calls function with first two consecutive elements in the sequence,
+obtains the result, calls function with the result and the subsequent element
+in the sequence and so on until the end of the list and returns the final result:</paragraph><literal_block>def mul(x, y):
+ return x*y
+
+>>> reduce(mul, [1, 2, 3, 4])
+24</literal_block>
+
+6.1. List Comprehensions
+<paragraph>List Comprehension is a convenvience utility provided by Python. It is a
+syntatic sugar to create Lists. Using List Comprehensions one can create
+Lists from other type of sequential data structures or other Lists itself.
+The syntax of List Comprehensions consists of a square brackets to indicate
+the result is a List within which we include at least one <strong>for</strong> clause and
+multiple <strong>if</strong> clauses. It will be more clear with an example:</paragraph><literal_block>>>> num = [1, 2, 3]
+>>> sq = [x*x for x in num]
+>>> sq
+[1, 4, 9]
+>>> all_num = [1, 2, 3, 4, 5, 6, 7, 8, 9]
+>>> even = [x for x in all_num if x%2 == 0]</literal_block><paragraph>The syntax used here is very clear from the way it is written. It can be
+translated into english as, "for each element x in the list all_num,
+if remainder of x divided by 2 is 0, add x to the list."</paragraph>
+