\documentclass[14pt,compress,aspectratio=169]{beamer} \usepackage{hyperref} \input{macros.tex} \title[OOP: more special methods]{Advanced Python} \subtitle{Object Oriented Programming: more special methods} \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{Special methods} \begin{itemize} \item \py{__init__} is one such method \item \py{__str__, __repr__} \item Many more \end{itemize} \end{frame} \begin{frame}[fragile] \frametitle{Motivation} \begin{lstlisting} class A: def __init__(self, x=0): self.x = x In []: a, b = A(), A() \end{lstlisting} \pause \begin{lstlisting} In []: a == b Out[]: False In []: a < b # ? \end{lstlisting} \end{frame} \begin{frame}[fragile] \frametitle{Comparison operators: rich comparison} \begin{itemize} \item \py{__lt__(self, other)}: \py{self < other} \item \py{__le__(self, other)}: \py{self <= other} \item \py{__gt__(self, other)}: \py{self > other} \item \py{__ge__(self, other)}: \py{self >= other} \item \py{__eq__(self, other)}: \py{self == other} \item \py{__ne__(self, other)}: \py{self != other} \vspace*{0.2in} \item \py{__bool__(self)}: used for truth values \end{itemize} \end{frame} \begin{frame}[fragile] \frametitle{Example} \small \begin{lstlisting} class A: def __init__(self, x=0): self.x = x def __eq__(self, other): return self.x == other.x def __lt__(self, other): return self.x < other.x \end{lstlisting} \pause \begin{lstlisting} In []: a, b = A(), B() In []: a == b Out[]: True In []: a.x = 1 In []: a == b Out[]: False \end{lstlisting} \end{frame} \begin{frame}[fragile] \frametitle{Container types} \begin{itemize} \item \py{__len__(self)}: \py{len(object)} \item \py{__getitem__(self, key)}: \py{object[key]} \item \py{__setitem__(self, key, value)}: \py{object[key] = value} \item \py{__delitem__(self, name)}: \py{del object[key]} \item \py{__iter__(self)}: \py{for x in object} \item \py{__contains__(self, item)}: \py{item in object} \end{itemize} \end{frame} \begin{frame} \frametitle{Emulating numeric types} \begin{itemize} \item \py{__add__(self, other)}: \py{object + other} \item \py{__sub__(self, other)}: \py{object - other} \item \py{__mul__(self, other)}: \py{object * other} \item \py{__div__(self, other)}: \py{object / other} \item \py{__matmul__(self, other)}: \py{object @ other} \item ... \item \py{__radd__(self, other)}: \py{other + object} \item \py{__rsub__(self, other)}: \py{other - object} \item More similar \end{itemize} \end{frame} \begin{frame} \frametitle{Emulating numeric types} \begin{itemize} \item \py{__iadd__(self, other)}: \py{object += other} \item \py{__isub__(self, other)}: \py{object -= other} \item ... \item \py{__neg__(self)}: \py{-object} \item \py{__pos__(self)}: \py{+object} \item \py{__abs__(self)}: \py{abs(object)} \item ... \item \py{__int__(self)}: \py{int(object)} \item \py{__float__(self)}: \py{float(object)} \end{itemize} \end{frame} \begin{frame}[fragile] \frametitle{Example} \begin{lstlisting} class A: def __init__(self, x=0): self.x = x def __add__(self, other): return A(self.x + other.x) In []: a, b = A(1), A(1) In []: c = a + b In []: print(c.x) 2 \end{lstlisting} \end{frame} \begin{frame}[fragile] \frametitle{Callable objects} \begin{itemize} \item \py{__call__(self [, args...])}: \py{object()} \end{itemize} \end{frame} \begin{frame}[fragile] \frametitle{Attribute access} \begin{itemize} \item \py{__getattr__(self, name)}: \py{self.name} \item \py{__getattribute__(self, name)}: \py{self.name} \item \py{__setattr__(self, name, value)}: \py{self.name = value} \item \py{__delattr__(self, name)}: \py{del self.name} \item \py{__dir__(self)}: \py{dir(object)} \end{itemize} \end{frame} \begin{frame} \frametitle{Doing more} \begin{itemize} \item Explore later \item See: \url{docs.python.org/reference/datamodel.html} \end{itemize} \end{frame} \begin{frame}[plain, fragile] \frametitle{Exercise: Animal weights} \begin{block}{} Create an \py{Animal} class with a \py{name} (str) and \py{weight} (float) attribute. Allow a user to perform rich comparisons of animals based on their weight (it should support all comparisons). For example: \end{block} \begin{lstlisting} In []: cat = Animal('cat', 5) In []: dog = Animal('dog', 10) In []: dog > cat Out[]: True \end{lstlisting} \end{frame} \begin{frame}[plain, fragile] \frametitle{Solution} \small \begin{lstlisting} class Animal: def __init__(self, name, weight=0.0): self.name = name self.weight = weight def __lt__(self, other): return self.weight < other.weight def __le__(self, other): return self.weight <= other.weight def __eq__(self, other): return self.weight == other.weight # ... \end{lstlisting} \end{frame} \begin{frame}[plain, fragile] \frametitle{Exercise: Zoo class container} \begin{block}{} Create a \py{Zoo} class which can contain animals. The Zoo should behave like a container. \end{block} \begin{lstlisting} In []: a = Animal('cat', 5) In []: b = Animal('dog', 10) In []: zoo = Zoo(a, b) In []: len(zoo) Out[]: 2 In []: a in zoo Out[]: True \end{lstlisting} Implement all other container related methods. \end{frame} \begin{frame}[plain, fragile] \frametitle{Solution} \vspace*{-0.1in} \small \begin{lstlisting} class Animal: def __init__(self, name, weight=0.0): self.name = name self.weight = weight class Zoo: def __init__(self, *animals): self.animals = list(animals) def __len__(self): return len(self.animals) def __contains__(self, item): return item in self.animals def __getitem__(self, key): return self.animals[key] def __iter__(self): return self.animals \end{lstlisting} \end{frame} \begin{frame}[plain, fragile] \frametitle{Exercise: \py{Point} class addition} \begin{block}{} Write a \py{Point} class with two instance attributes \py{x, y}. Make it possible to add and subtract two points. Also allow \py{abs()} to be callable on a point. \end{block} \begin{lstlisting} In []: p1 = Point(1, 2) In []: p2 = Point(1, 0) In []: p = p1 + p2 In []: p.x, p.y Out[]: (2, 2) In []: abs(p) Out[]: 2.8284271247461903 \end{lstlisting} \end{frame} \begin{frame}[plain, fragile] \frametitle{Solution} \small \begin{lstlisting} from math import sqrt class Point: def __init__(self, x=0, y=0): self.x = x self.y = y def __add__(self, other): return Point(self.x + other.x, self.y + other.y) def __sub__(self, other): return Point(self.x - other.x, self.y - other.y) def __abs__(self): return sqrt(self.x*self.x + self.y*self.y) \end{lstlisting} \end{frame} \end{document}