\section{Functions}

\begin{frame}[fragile]
  \frametitle{Abstracting}
  \begin{itemize}
  \item Reduce duplication of code
  \item Fewer lines of code and hence lesser scope for bugs
  \item Re-usability of code, that's already been written
  \item Use functions written by others, without exactly knowing how
    they do, what they are doing
  \item \alert{Enter Functions!}
  \end{itemize}
\end{frame}


\begin{frame}[fragile]
  \frametitle{Defining functions}
  \begin{itemize}
  \item Consider the function \texttt{f(x) = x\textasciicircum{}2}
  \item Let's write a Python function, equivalent to this
  \end{itemize}
  \begin{lstlisting}
    def f(x):
        return x*x

    f(1)
    f(2)
  \end{lstlisting}
  \begin{itemize}
  \item \texttt{def} is a keyword  
  \item \texttt{f} is the name of the function 
  \item \texttt{x} the parameter of the function
  \item \texttt{return} is a keyword; specifies what should be
    returned
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Defining functions \ldots}
  \begin{lstlisting}
    def greet():
        print "Hello World!"

    greet()
  \end{lstlisting}
  \begin{itemize}
  \item \texttt{greet} is a function that takes no arguments
  \item Also, it is not returning anything explicitly
  \item But implicitly, Python returns \texttt{None}
  \end{itemize}
  \begin{lstlisting}
    def avg(a, b):
        return (a + b)/2
        
    avg(12, 10)
  \end{lstlisting}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Doc-strings}
  \begin{itemize}
  \item It's highly recommended that all functions have documentation
  \item We write a doc-string along with the function definition
  \end{itemize}
  \begin{lstlisting}
    def avg(a, b):
        """ avg takes two numbers as input 
        and returns their average"""

        return (a + b)/2
        
    avg?
    greet?
  \end{lstlisting}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Returning multiple values}
  \begin{itemize}
  \item Return area and perimeter of circle, given radius
  \item Function needs to return two values
  \end{itemize}
  \begin{lstlisting}
    def circle(r):
        """returns area and perimeter of a 
        circle given, the radius r"""

        pi = 3.14
        area = pi * r * r
        perimeter = 2 * pi * r
        return area, perimeter

    circle(4)
    a, p = circle(6)
    print a
    print p
  \end{lstlisting}
  \begin{itemize}
  \item Any number of values can be returned
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{What? -- 1}
  \begin{lstlisting}       
    def what( n ):           
        if n < 0: n = -n     
        while n > 0:         
            if n % 2 == 1:   
                return False 
            n /= 10          
        return True          
  \end{lstlisting}         
\end{frame}

\begin{frame}[fragile]
  \frametitle{What? -- 2}
  \begin{lstlisting}
    def what( n ):
        i = 1
        while i * i < n:
            i += 1
        return i * i == n, i
  \end{lstlisting}
\end{frame}

\subsection*{Default \& Keyword Arguments}

\begin{frame}[fragile]
  \frametitle{Default arguments}
  \begin{lstlisting}
    round(2.484)
    round(2.484, 2)

    s.split() # split on spaces
    s.split(';') # split on ';'

    range(10) # returns numbers from 0 to 9
    range(1, 10) # returns numbers from 1 to 9
    range(1, 10, 2) # returns odd numbers from 1 to 9
  \end{lstlisting}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Default arguments \ldots}
  \begin{lstlisting}
    def welcome(greet, name="World"):
        print greet, name

    welcome("Hi", "Guido")
    welcome("Hello")
  \end{lstlisting}
  \begin{itemize}
  \item Arguments with default values, should be placed at the end
  \item The following definition is \alert{WRONG}
  \end{itemize}
  \begin{lstlisting}
    def welcome(name="World", greet):
        print greet, name
  \end{lstlisting}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Keyword Arguments}
  \begin{lstlisting}
    def welcome(greet, name="World"):
        print greet, name

    welcome("Hello", "James")

    welcome("Hi", name="Guido")

    welcome(name="Guido", greet="Hey")

    welcome(name="Guido", "Hey")
  \end{lstlisting}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Built-in functions}
  \begin{itemize}
  \item Variety of built-in functions are available
  \item \texttt{abs, any, all, len, max, min}
  \item \texttt{pow, range, sum, type}
  \item Refer here:
    \url{http://docs.python.org/library/functions.html}
  \end{itemize}
\end{frame}

\subsection*{Variable Scope}

\begin{frame}[fragile]
  \frametitle{Arguments are local}
  \begin{lstlisting}
    def change(q):
        q = 10
        print q

    change(1)
    print q
  \end{lstlisting}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Variables inside function are local}
  \begin{lstlisting}
    n = 5
    def change():
        n = 10
        print n
    change()
    print n
  \end{lstlisting}
  \begin{itemize}
  \item Use the \texttt{global} statement to assign to global variables
  \end{itemize}
  \begin{lstlisting}
    def change():
        global n
        n = 10
        print n
    change()
    print n
  \end{lstlisting}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Mutable variables}
  \begin{itemize}
  \item Behavior is different when assigning to a list element/slice
  \item Python looks up for the name, from innermost scope outwards,
    until the name is found
  \end{itemize}
  \begin{lstlisting}
    name = ['Mr.', 'Steve', 'Gosling']
    def change_name():
        name[0] = 'Dr.'
    change_name()
    print name
  \end{lstlisting}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Passing Arguments \ldots}
  \begin{lstlisting}
    n = 5
    def change(n):
        n = 10
        print "n = %s inside change " %n
    change(n)
    print n
  \end{lstlisting}
  
  \begin{lstlisting}
    name = ['Mr.', 'Steve', 'Gosling']
    def change_name(n):
        n[0] = 'Dr.'
        print "n = %s inside change_name" %n
    change_name(name)
    print name
  \end{lstlisting}
\end{frame}