\documentclass[14pt,compress,aspectratio=169]{beamer}

\input{macros.tex}

\title[OOP Inheritance]{Advanced Python}
\subtitle{Object Oriented Programming: Inheritance}

\author[FOSSEE] {The FOSSEE Group}

\institute[IIT Bombay] {Department of Aerospace Engineering\\IIT Bombay}
\date[] {Mumbai, India}

\begin{document}

\begin{frame}
  \titlepage
\end{frame}

\begin{frame}
  \frametitle{Recap}
  \begin{itemize}
  \item Created a new \lstinline{Talk} class
  \item Puts together data and methods
  \item Can make instances of the class
  \item Each instance has its own data
  \item Objects encapsulate data and behavior
  \end{itemize}
\end{frame}

\begin{frame}[fragile, plain]
  \frametitle{Recap: the Talk class}
  \vspace*{-0.1in}
  \begin{lstlisting}
class Talk:
    """A class for the Talks."""
    def __init__(self, speaker, title, tags):
        self.speaker = speaker
        self.title = title
        self.tags = tags

    def get_speaker_firstname(self):
        return self.speaker.split()[0]

    def get_tags(self):
        return self.tags.split(',')
  \end{lstlisting}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Instantiating a class to create objects}
  \begin{lstlisting}
In []: bdfl = Talk('Guido van Rossum',
  ...:             'The History of Python',
  ...:             'python,history,C,advanced')
In []: bdfl.get_tags()
In []: bdfl.get_speaker_firstname()
In []: bdfl.tags

In []: type(bdfl)
  \end{lstlisting}
\end{frame}


\begin{frame}[fragile]
  \frametitle{Classes: the big picture}
  \begin{itemize}
  \item Lets you create new data types
  \item Class is a template for an object belonging to that class
  \item Instantiating a class creates an instance (an object)
  \item An instance encapsulates the state (data) and behavior
    (methods)
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Objects and Methods}
  \begin{itemize}
  \item Objects group data with functions
  \item Everything in Python is an object
  \item Strings, lists, functions and even modules
  \end{itemize}
  \begin{lstlisting}
    s = "Hello World"
    s.lower()

    l = [1, 2, 3, 4, 5]
    l.append(6)
  \end{lstlisting}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Classes}
  \begin{lstlisting}
In []: s = "Hello World"
In []: type(s)
  \end{lstlisting}
  \begin{itemize}
  \item A new string, comes along with methods
  \item A template or a blue-print, where these definitions lie
  \item This blue print for building objects is called a
    \lstinline{class}
  \item \lstinline{s} is an object of the \lstinline{str} class
  \item An object is an ``instance'' of a class
  \end{itemize}
\end{frame}


\begin{frame}[fragile]
  \frametitle{Classes: inheritance}
  \begin{itemize}
  \item Allows you to define an inheritance hierarchy
    \begin{itemize}
    \item ``A Honda car \alert{is a} car.''
    \item ``A car \alert{is an} automobile.''
    \item ``A Python \alert{is a} reptile.''
    \end{itemize}
  \item All data/behavior of a car should be there in a ``Honda'' car
  \item All data/behavior associated with a reptile ought to inhere in a snake
  \end{itemize}
\end{frame}


\begin{frame}[fragile]
  \frametitle{Inheritance}
  \vspace*{-0.1in}
  \begin{itemize}
  \item Suppose, we wish to write a \lstinline{Tutorial} class
  \item It's almost same as \lstinline{Talk} except for minor differences
  \item We can ``inherit'' from \lstinline{Talk}
  \end{itemize}
  \pause
  \begin{lstlisting}
class Tutorial(Talk):
    """A class for the tutorials."""
    def __init__(self, speaker, title, tags,
                 needs_computer=True):
        super().__init__(speaker, title, tags)
        self.needs_computer = needs_computer
  \end{lstlisting}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Inheritance}
  \vspace*{-0.1in}
  \begin{itemize}
  \item Modified \lstinline{__init__} method
  \item Inherits: \lstinline{get_tags} and
    \lstinline{get_speaker_firstname}
  \end{itemize}
  \begin{lstlisting}
tut = Tutorial('Travis Oliphant',
               'Numpy Basics',
               'numpy,python,beginner')
tut.get_speaker_firstname()
tut.needs_computer
  \end{lstlisting}
\end{frame}

\begin{frame}
  \frametitle{Some points}
  \begin{itemize}
  \item \lstinline{Tutorial} is a subclass (or child) of \lstinline{Talk}
  \item \lstinline{Tutorial} is derived from (inherits from) \lstinline{Talk}
  \item \lstinline{Talk} is the base class (or parent class)
  \item Only the \lstinline{__init__} has been changed
  \item This is called overriding
  \item \lstinline{super} ensures that the parent class is called
  \item Calling the parent is not automatic
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Exercise: try this}
\begin{lstlisting}
class Tutorial(Talk):
    def __init__(self, speaker, title, tags,
                 needs_computer=True):
        self.needs_computer = needs_computer

In []: t = Tutorial('G v R', 'Python', 'py,tut')

In []: t.needs_computer

In []: t.speaker

In []: t.get_speaker_firstname()

\end{lstlisting}
\end{frame}

\begin{frame}
  \frametitle{Inheritance}
  \begin{itemize}
  \item A \lstinline{Tutorial} is a \lstinline{Talk}
  \item A \lstinline{Talk} is not a \lstinline{Tutorial}
  \item The sentence above should make sense!
  \item A \lstinline{Cat} is an \lstinline{Animal}
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{Incorrect inheritance}
  \begin{itemize}
  \item A \lstinline{Talk} is a \lstinline{Speaker} or
  \item A \lstinline{Speaker} is a \lstinline{Room}
  \item Something is wrong in your OO design!
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Summary}
  \begin{itemize}
  \item Inheritance
  \item The importance of making sense
  \item The \lstinline{super} function
  \end{itemize}
\end{frame}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Exercises

\begin{frame}[fragile]
  \frametitle{Exercise: \lstinline{Animal} class}
  \begin{block}{}
    Create an \lstinline{Animal} class that has a name attribute (str) and a
    single method called \lstinline{greet} which takes no arguments but returns
    a string about how the animal makes a greeting.  By default let
    \lstinline{greet} return \lstinline{'<name> says greet'}.
  \end{block}
\begin{lstlisting}
In []: a = Animal('human')
In []: a.greet()
Out[]: 'human says greet'
\end{lstlisting}
\end{frame}

\begin{frame}[plain, fragile]
  \frametitle{Solution}
\begin{lstlisting}
class Animal:
    def __init__(self, name):
        self.name = name
    def greet(self):
        return self.name + ' says greet'
\end{lstlisting}
\end{frame}

\begin{frame}[plain, fragile]
  \frametitle{Solution}
  \begin{itemize}
  \item Note that this is the same as
  \end{itemize}
\begin{lstlisting}
class Animal(object):
    # ...
\end{lstlisting}
  \begin{itemize}
  \item Otherwise \lstinline{object} is implicitly the base class
  \end{itemize}

\end{frame}

\begin{frame}[fragile]
  \frametitle{Exercise: \lstinline{Cat} class}
  \begin{block}{}
    Create a \lstinline{Cat} class which derives from the \lstinline{Animal}
    class \alert{override} \lstinline{greet} return
    \lstinline{'<name> says meow'}.
  \end{block}
\begin{lstlisting}
In []: a = Cat('Felix')
In []: a.greet()
Out[]: 'Felix says meow'
\end{lstlisting}
\end{frame}


\begin{frame}[plain, fragile]
  \frametitle{Solution}
\begin{lstlisting}
class Animal:
    def __init__(self, name):
        self.name = name
    def greet(self):
        return self.name + ' says greet'

class Cat(Animal):
    def greet(self):
        return self.name + ' says meow'
\end{lstlisting}
  \begin{itemize}
  \item Note, no need to override \lstinline{__init__}
  \end{itemize}
\end{frame}

\begin{frame}[plain, fragile]
  \frametitle{Observation: order matters}
\begin{lstlisting}
class Cat(Animal):
    def greet(self):
        return self.name + ' says meow'

class Animal:
    def __init__(self, name):
        self.name = name
    def greet(self):
        return self.name + ' says greet'

\end{lstlisting}
  \begin{itemize}
  \item Will the above code work? Explore this and see what error you get.
  \end{itemize}
\end{frame}


\begin{frame}[plain, fragile]
  \frametitle{Exercise: \lstinline{Mammal} class}
  \begin{block}{}
    Create a \lstinline{Mammal} class that derives from \lstinline{Animal}
    that takes an additional argument specifying the number of legs (an
    integer) and stores it in the attribute \lstinline{legs}.
  \end{block}

\begin{lstlisting}
In []: m = Mammal('dog', 4)
In []: m.legs
Out[]: 4
In []: m.greet()
Out[]: 'dog says greet'
\end{lstlisting}
\end{frame}


\begin{frame}[plain, fragile]
  \frametitle{Solution}
\begin{lstlisting}
class Mammal(Animal):
    def __init__(self, name, legs):
        super().__init__(name)
        self.legs = legs
\end{lstlisting}
\end{frame}


\begin{frame}[plain, fragile]
  \frametitle{Solution alternative}
\begin{lstlisting}
class Mammal(Animal):
    def __init__(self, name, legs):
        self.name = name
        self.legs = legs
\end{lstlisting}
  \begin{itemize}
  \item Will also work but a \alert{bad} idea
  \item What if \lstinline{Animal.__init__} changes?
  \end{itemize}
\end{frame}

\begin{frame}[plain, fragile]
  \frametitle{More on \typ{super}}
We can also do:
\begin{lstlisting}
class Mammal(Animal):
    def __init__(self, name, legs):
        super(Mammal, self).__init__(name)

In []: super?

In []: m = Mammal('dog', 4)
In []: super(Mammal, m)

In []: super(Mammal, m).greet()

In []: super(Animal, m).greet() # ??
\end{lstlisting}
\end{frame}


\begin{frame}[plain, fragile]
  \frametitle{Exercise: \lstinline{Human} class}
  \begin{block}{}
    Create a \lstinline{Human} class that derives from \lstinline{Mammal}
    modify its \lstinline{greet} method to return
    \lstinline{'<name> says hello'}.  Also change the default number of legs
    to 2.
  \end{block}

\begin{lstlisting}
In []: h = Human('Ram')
In []: h.legs
Out[]: 2
In []: h.greet()
Out[]: 'Ram says hello'
\end{lstlisting}
\end{frame}

\begin{frame}[plain, fragile]
  \frametitle{Solution}
\begin{lstlisting}
class Human(Mammal):
    def __init__(self, name, legs=2):
        super().__init__(name, legs)
    def greet(self):
        return self.name + ' says hello'
\end{lstlisting}
\end{frame}

\begin{frame}[plain, fragile]
  \frametitle{Complete Solution}
  \vspace*{-0.1in}
  \small
\begin{lstlisting}
class Animal:
    def __init__(self, name):
        self.name = name
    def greet(self):
        return self.name + ' says greet'

class Mammal(Animal):
    def __init__(self, name, legs):
        super().__init__(name)
        self.legs = legs

class Human(Mammal):
    def __init__(self, name, legs=2):
        super().__init__(name, legs)
    def greet(self):
        return self.name + ' says hello'
\end{lstlisting}
\end{frame}

\begin{frame}
  \frametitle{Observations}
  \begin{itemize}
  \item \py{Human} is a \py{Mammal}
  \item \py{Human} is an \py{Animal}
  \end{itemize}
\end{frame}


\begin{frame}[plain, fragile]
  \frametitle{Exercise: Methods in subclass}
  \begin{block}{}
    Add a method to \py{Human} called \py{speak} which prints
    \py{'My name is <name>'}.
  \end{block}

\begin{lstlisting}
In []: h = Human('Ram')
In []: h.speak()
My name is Ram
\end{lstlisting}
\end{frame}


\begin{frame}[plain, fragile]
  \frametitle{Solution}
\begin{lstlisting}
class Human(Mammal):
    def __init__(self, name, legs=2):
        super().__init__(name, legs)
    def greet(self):
        return self.name + ' says hello'
    def speak(self):
        print('My name is', self.name)
\end{lstlisting}
\end{frame}

\begin{frame}
  \frametitle{Observations}
  \begin{itemize}
  \item \py{Human} is a \py{Mammal}
  \item \py{Human} is an \py{Animal}
  \item \py{Human} can speak but \py{Mammal, Animal} cannot
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Exercise: class in a module}

  \begin{block}{}
    Put the \py{Animal, Mammal, Human} classes inside a Python file, called
    \texttt{oop.py} somewhere convenient in your computer.  Add the following
    code at the bottom.
  \end{block}
\begin{lstlisting}
print(__name__)
h = Human('Sam')
print(h.greet())
print(h.legs)
print(type(h))
\end{lstlisting}

  \begin{itemize}
  \item Execute this module using \texttt{python oop.py}
  \item Import the \py{Human} class from IPython
  \end{itemize}
\end{frame}

\begin{frame}[plain, fragile]
  \frametitle{Exercise: overriding a \typ{list} method}
  \begin{block}{}
    Create a subclass of the standard Python \py{list} called \py{MyList} and
    override just the \py{append} method to print the item appended as
    \py{'appending <item>'} and then call the parent append so as to
    internally append the item. The usage should be as follows:
  \end{block}

\begin{lstlisting}
In []: l = MyList()
In []: l.append(1)
appending 1
In []: l
Out[]: [1]
\end{lstlisting}
\end{frame}


\begin{frame}[plain, fragile]
  \frametitle{Solution}
\begin{lstlisting}
class MyList(list):
    def append(self, item):
        print('appending', item)
        super().append(item)
\end{lstlisting}
\end{frame}



\end{document}