dive into object-oriented python

173

Upload: giordanileonardo

Post on 14-Jan-2017

1.193 views

Category:

Software


9 download

TRANSCRIPT

Page 1: Dive into Object-oriented Python
Page 2: Dive into Object-oriented Python

https://github.com/lgiordani/oopy

IPython NotebooksPyConIE_2015/notebooks

Python 3 codePyConIE_2015/code/python3

Python 2 codePyConIE_2015/code/python2

Page 3: Dive into Object-oriented Python

I'm a software engineer, coder since around 1988, Linux user since 1998, Python lover since 1999.

Currently working with Python and C in the field of satellite remote sensing.

During the last 27 years I worked with Z80, Motorola 68k and Intel x86 Assembly, BASIC, Pascal, Prolog, C, LISP, bash, Python, C++, Erlang, JavaScript, Scala, Clojure.

about me

The Digital Cat

lgiordani.comhttps://twitter.com/

tw_lgiordanihttps://github.com/

lgiordanihttps://plus.google.com/u/

LeonardoGiordani

Page 4: Dive into Object-oriented Python

import levelsfrom pyconie2015 import oop_workshop

def can_understand(user):return user.level >= levels.BEGINNER

for you in oop_workshop.attendees:assert can_understand(you)

about_you.py

Page 5: Dive into Object-oriented Python

jupyter notebooks

http://jupyter.org/

#!/bin/bash

sudo apt-get install -y python3-dev build-essential

virtualenv -p python3 venv3 source venv3/bin/activate

pip install -U pippip install jupyter

jupyter notebook

http://jupyter.readthedocs.org/en/latest/install.html

Page 6: Dive into Object-oriented Python

ABOUT THIS TUTORIAL

3Objects and types

Classes and members

Delegation

Polymorphism

Page 7: Dive into Object-oriented Python

PART 1

Objects and types

Page 8: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

data = (13, 63, 5, 378, 58, 40)

def avg(d): return sum(d)/len(d)

>>> avg(data)92.83333333333333

Plain old procedures

Page 9: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

door1 = [1, 'closed']door2 = [2, 'closed']

def open_door(door): door[1] = 'open'

>>> open_door(door1)>>> door1[1, 'open']

Procedures can modify data

Page 10: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

door1 = [1, 'closed']door2 = [2, 'closed']

ldoor1 = [1, 'closed', 'unlocked']

def open_door(door): door[1] = 'open'

def open_ldoor(door): if door[2] == 'unlocked': door[1] = 'open'

Things can get complicated

Page 11: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

door1 = [1, 'closed']door2 = [2, 'closed']

ldoor1 = [1, 'closed', 'unlocked']

def open_door(door): door[1] = 'open'

def open_ldoor(door): if door[2] == 'unlocked': door[1] = 'open'

>>> open_door(door1)>>> door1[1, 'open']

>>> open_ldoor(ldoor1)>>> ldoor1[1, 'open', 'unlocked']

Things can get complicated

Page 12: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Behavioural meaning

The meaning of the word 'type'

Page 13: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Structural meaning

The meaning of the word 'type'

Page 14: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

The behavioural meaning is important

Page 15: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

The meaning of the word 'class'

Page 16: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

The meaning of the word 'instance'

Page 17: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> a = 6>>> a6

>>> type(a)<class 'int'>

>>> a = int(6)>>> a6

>>> a.__class__<class 'int'>

You already used classes

Page 18: Dive into Object-oriented Python

Python

2.x

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

You already used classes

>>> a = 6>>> a6

>>> type(a)<type 'int'>

>>> a = int(6)>>> a6

>>> a.__class__<type 'int'>

Page 19: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises

1. Find some types that Python provides out of the box.

2. Can you create a float variable without using the '.' character?

3. What is the difference between {1,2,3} and {'a':1, 'b':2}?

Page 20: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises1. Find some types that Python provides out of the box.

>>> type(4)<class 'int'>>>> type(4.5)<class 'float'>>>> type('some words')<class 'str'>>>> type([1,2,3,4])<class 'list'>>>> type((1,2,3,4))<class 'tuple'>>>> type({1,2,3,4})<class 'set'>>>> type({'first name':'Ray', 'last name':'Stantz'})<class 'dict'>>>> type(True)<class 'bool'>

Page 21: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises

2. Can you create a float variable without using the '.' character?

>>> a = float(4)>>> type(a)<class 'float'>

Page 22: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises

3. What is the difference between {1,2,3} and {'a':1, 'b':2}?

>>> type({1,2,3})<class 'set'>>>> type({'a':1, 'b':2})<class 'dict'>

Page 23: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> door1 = Door(1, 'closed')>>> type(door1)<class Door>

Keep data and functions together

Page 24: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> door1 = Door(1, 'closed')>>> type(door1)<class Door>>>> door1.number1>>> door1.status'closed'

Keep data and functions together

Page 25: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> door1 = Door(1, 'closed')>>> type(door1)<class Door>>>> door1.number1>>> door1.status'closed'>>> door1.open()

Keep data and functions together

Page 26: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> door1 = Door(1, 'closed')>>> type(door1)<class Door>>>> door1.number1>>> door1.status'closed'>>> door1.open()>>> door1.number1>>> door1.status'open'

Keep data and functions together

Page 27: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

The first class

class Door: def __init__(self, number, status): self.number = number self.status = status

def open(self): self.status = 'open'

def close(self): self.status = 'closed'

Page 28: Dive into Object-oriented Python

Python

2.x

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

The first class

class Door(object): def __init__(self, number, status): self.number = number self.status = status

def open(self): self.status = 'open'

def close(self): self.status = 'closed'

Page 29: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

The first class

class Door: def __init__(self, number, status): self.number = number self.status = status

def open(self): self.status = 'open'

def close(self): self.status = 'closed'

Page 30: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

The first class

class Door: def __init__(self, number, status): self.number = number self.status = status

def open(self): self.status = 'open'

def close(self): self.status = 'closed'

Page 31: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

The first class

class Door: def __init__(self, number, status): self.number = number self.status = status

def open(self): self.status = 'open'

def close(self): self.status = 'closed'

Page 32: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

The first class

class Door: def __init__(self, number, status): self.number = number self.status = status

def open(self): self.status = 'open'

def close(self): self.status = 'closed'

Page 33: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> door1 = Door(1, 'closed')

The first class

class Door: def __init__(self, number, status): self.number = number self.status = status

def open(self): self.status = 'open'

def close(self): self.status = 'closed'

Page 34: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> door1 = Door(1, 'closed')>>> type(door1)<class '__main__.Door'>

The first class

class Door: def __init__(self, number, status): self.number = number self.status = status

def open(self): self.status = 'open'

def close(self): self.status = 'closed'

Page 35: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> door1 = Door(1, 'closed')>>> type(door1)<class '__main__.Door'>>>> door1.number1>>> door1.status'closed'

The first class

class Door: def __init__(self, number, status): self.number = number self.status = status

def open(self): self.status = 'open'

def close(self): self.status = 'closed'

Page 36: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> door1 = Door(1, 'closed')>>> type(door1)<class '__main__.Door'>>>> door1.number1>>> door1.status'closed'>>> door1.open()

The first class

class Door: def __init__(self, number, status): self.number = number self.status = status

def open(self): self.status = 'open'

def close(self): self.status = 'closed'

Page 37: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> door1 = Door(1, 'closed')>>> type(door1)<class '__main__.Door'>>>> door1.number1>>> door1.status'closed'>>> door1.open()>>> door1.number1>>> door1.status'open'

The first class

class Door: def __init__(self, number, status): self.number = number self.status = status

def open(self): self.status = 'open'

def close(self): self.status = 'closed'

Page 38: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises

1. Create a ColouredDoor class that has the 'colour' attribute.

2. Create a ClosedDoor class that has a default status of 'closed'.

3. Create a ToggleDoor class that has a method toggle() that toggles the status of the door.

Page 39: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises

1. Create a ColouredDoor class that has the 'colour' attribute.class ColouredDoor: def __init__(self, number, status, colour): self.number = number self.status = status self.colour = colour

def open(self): self.status = 'open'

def close(self): self.status = 'closed'

Page 40: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises

2. Create a ClosedDoor class that has a default status of 'closed'.class ClosedDoor: def __init__(self, number, status='closed'): self.number = number self.status = status

def open(self): self.status = 'open'

def close(self): self.status = 'closed'

Page 41: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises3. Create a ToggleDoor class that has a method toggle() that toggles the status of the door.

class ToggleDoor: def __init__(self, number, status): self.number = number self.status = status

def open(self): self.status = 'open'

def close(self): self.status = 'closed'

def toggle(self): d = {'open': 'closed', 'closed': 'open'} self.status = d[self.status]

Page 42: Dive into Object-oriented Python

PART 2

Classes and members

Page 43: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Where is the class of an object?

>>> door1 = Door(1, 'closed')>>> door2 = Door(1, 'closed')

Page 44: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Where is the class of an object?

>>> door1 = Door(1, 'closed')>>> door2 = Door(1, 'closed')>>> hex(id(door1))'0xb67e148c'>>> hex(id(door2))'0xb67e144c'

Page 45: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Where is the class of an object?

>>> door1 = Door(1, 'closed')>>> door2 = Door(1, 'closed')>>> hex(id(door1))'0xb67e148c'>>> hex(id(door2))'0xb67e144c'>>> hex(id(door1.__class__))'0xb685f56c'>>> hex(id(door2.__class__))'0xb685f56c'

Page 46: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Class attributes

class Door: colour = 'brown'

def __init__(self, number, status): self.number = number self.status = status

def open(self): self.status = 'open'

def close(self): self.status = 'closed'

Page 47: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> door1 = Door(1, 'closed')>>> door2 = Door(2, 'closed')

Class attributes

Page 48: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> door1 = Door(1, 'closed')>>> door2 = Door(2, 'closed')>>> Door.colour'brown'>>> door1.colour'brown'>>> door2.colour'brown'

Class attributes

Page 49: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.colour = 'white'

Class attributes

Page 50: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.colour = 'white'>>> Door.colour'white'>>> door1.colour'white'>>> door2.colour'white'

Class attributes

Page 51: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.colour = 'white'>>> Door.colour'white'>>> door1.colour'white'>>> door2.colour'white'>>> hex(id(Door.colour))'0xb67e1500'>>> hex(id(door1.colour))'0xb67e1500'>>> hex(id(door2.colour))'0xb67e1500'

Class attributes

Page 52: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.__dict__mappingproxy({'open': <function Door.open at 0xb68604ac>, 'colour': 'white', '__dict__': <attribute '__dict__' of 'Door' objects>, '__weakref__': <attribute '__weakref__' of 'Door' objects>, '__init__': <function Door.__init__ at 0xb7062854>, '__module__': '__main__', '__doc__': None, 'close': <function Door.close at 0xb686041c>})

Class attributes

Page 53: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.__dict__mappingproxy({'open': <function Door.open at 0xb68604ac>, 'colour': 'white', '__dict__': <attribute '__dict__' of 'Door' objects>, '__weakref__': <attribute '__weakref__' of 'Door' objects>, '__init__': <function Door.__init__ at 0xb7062854>, '__module__': '__main__', '__doc__': None, 'close': <function Door.close at 0xb686041c>})>>> door1.__dict__{'number': 1, 'status': 'closed'}

Class attributes

Page 54: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.__dict__mappingproxy({'open': <function Door.open at 0xb68604ac>, 'colour': 'white', '__dict__': <attribute '__dict__' of 'Door' objects>, '__weakref__': <attribute '__weakref__' of 'Door' objects>, '__init__': <function Door.__init__ at 0xb7062854>, '__module__': '__main__', '__doc__': None, 'close': <function Door.close at 0xb686041c>})>>> door1.__dict__{'number': 1, 'status': 'closed'}>>> door1.__dict__['colour']Traceback (most recent call last): File "<stdin>", line 1, in <module>KeyError: 'colour'

Class attributes

Page 55: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.__dict__mappingproxy({'open': <function Door.open at 0xb68604ac>, 'colour': 'white', '__dict__': <attribute '__dict__' of 'Door' objects>, '__weakref__': <attribute '__weakref__' of 'Door' objects>, '__init__': <function Door.__init__ at 0xb7062854>, '__module__': '__main__', '__doc__': None, 'close': <function Door.close at 0xb686041c>})>>> door1.__dict__{'number': 1, 'status': 'closed'}>>> door1.__dict__['colour']Traceback (most recent call last): File "<stdin>", line 1, in <module>KeyError: 'colour'>>> door1.__class__.__dict__['colour']'white'>>> door1.colour is Door.colourTrue

Class attributes

Page 56: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Door

door1 door2

__getattribute__()__getattribute__()

Let's dive into attribute resolution

door1.colour

Door.colour

Page 57: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Let's dive into attribute resolution

>>> door1 = Door(1, 'closed')>>> door1.colour = 'white'>>> door1.__dict__['colour']'white'>>> door1.__class__.__dict__['colour']'brown'

Page 58: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Let's dive into attribute resolution

>>> door1 = Door(1, 'closed')>>> door1.colour = 'white'>>> door1.__dict__['colour']'white'>>> door1.__class__.__dict__['colour']'brown'>>> door1.colour'white'>>> Door.colour'brown'

Page 59: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Let's dive into attribute resolution

>>> door1 = Door(1, 'closed')>>> door1.colour = 'white'>>> door1.__dict__['colour']'white'>>> door1.__class__.__dict__['colour']'brown'>>> door1.colour'white'>>> Door.colour'brown'>>> Door.colour = 'red'

Page 60: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Let's dive into attribute resolution

>>> door1 = Door(1, 'closed')>>> door1.colour = 'white'>>> door1.__dict__['colour']'white'>>> door1.__class__.__dict__['colour']'brown'>>> door1.colour'white'>>> Door.colour'brown'>>> Door.colour = 'red'>>> door1.__dict__['colour']'white'>>> door1.__class__.__dict__['colour']'red'

Page 61: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises

1. Modify the Door class adding a class attribute 'status' with value 'undefined'. Does it work? What happens to instances?

2. Modify the Door class adding a class attribute 'status' with value 'closed' and remove status from __init__(). Does it work?

3. Add a toggle() method to the previous class. What happens if you call toggle() on a fresh instance? Why?

Page 62: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises

1. Modify the Door class adding a class attribute 'status' with value 'undefined'. Does it work? What happens to instances?

class Door: colour = 'brown' status = 'undefined'

def __init__(self, number, status): self.number = number self.status = status

def open(self): self.status = 'open'

def close(self): self.status = 'closed'

Page 63: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises

2. Modify the Door class adding a class attribute 'status' with value 'closed' and remove status from __init__(). Does it work?

class Door: colour = 'brown' status = 'closed'

def __init__(self, number): self.number = number

def open(self): self.status = 'open'

def close(self): self.status = 'closed'

Page 64: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises

3. Add a toggle() method to the previous class. What happens if you call toggle() on a fresh instance? Why?

class Door: colour = 'brown' status = 'closed'

def __init__(self, number): self.number = number

def toggle(self): d = {'open': 'closed', 'closed': 'open'} self.status = d[self.status]

Page 65: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.__dict__mappingproxy({'open': <function Door.open at 0xb68604ac>, 'colour': 'white', '__dict__': <attribute '__dict__' of 'Door' objects>, '__weakref__': <attribute '__weakref__' of 'Door' objects>, '__init__': <function Door.__init__ at 0xb7062854>, '__module__': '__main__', '__doc__': None, 'close': <function Door.close at 0xb686041c>})>>> door1.__dict__{'number': 1, 'status': 'closed'}>>> door1.colour is Door.colourTrue

What about methods?

Page 66: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.__dict__mappingproxy({'open': <function Door.open at 0xb68604ac>, 'colour': 'white', '__dict__': <attribute '__dict__' of 'Door' objects>, '__weakref__': <attribute '__weakref__' of 'Door' objects>, '__init__': <function Door.__init__ at 0xb7062854>, '__module__': '__main__', '__doc__': None, 'close': <function Door.close at 0xb686041c>})>>> door1.__dict__{'number': 1, 'status': 'closed'}>>> door1.colour is Door.colourTrue>>> door1.open is Door.openFalse

What about methods?

Page 67: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.__dict__mappingproxy({'open': <function Door.open at 0xb68604ac>, 'colour': 'white', '__dict__': <attribute '__dict__' of 'Door' objects>, '__weakref__': <attribute '__weakref__' of 'Door' objects>, '__init__': <function Door.__init__ at 0xb7062854>, '__module__': '__main__', '__doc__': None, 'close': <function Door.close at 0xb686041c>})>>> door1.__dict__{'number': 1, 'status': 'closed'}>>> door1.colour is Door.colourTrue>>> door1.open is Door.openFalse>>> Door.__dict__['open']<function Door.open at 0xb68604ac>>>> Door.open<function Door.open at 0xb68604ac>

What about methods?

Page 68: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.__dict__mappingproxy({'open': <function Door.open at 0xb68604ac>, 'colour': 'white', '__dict__': <attribute '__dict__' of 'Door' objects>, '__weakref__': <attribute '__weakref__' of 'Door' objects>, '__init__': <function Door.__init__ at 0xb7062854>, '__module__': '__main__', '__doc__': None, 'close': <function Door.close at 0xb686041c>})>>> door1.__dict__{'number': 1, 'status': 'closed'}>>> door1.colour is Door.colourTrue>>> door1.open is Door.openFalse>>> Door.__dict__['open']<function Door.open at 0xb68604ac>>>> Door.open<function Door.open at 0xb68604ac>>>> door1.open<bound method Door.open of <__main__.Door object at 0xb67e162c>>

What about methods?

Page 69: Dive into Object-oriented Python

Python

2.x

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.__dict__mappingproxy({'open': <function Door.open at 0xb68604ac>, 'colour': 'white', '__dict__': <attribute '__dict__' of 'Door' objects>, '__weakref__': <attribute '__weakref__' of 'Door' objects>, '__init__': <function Door.__init__ at 0xb7062854>, '__module__': '__main__', '__doc__': None, 'close': <function Door.close at 0xb686041c>})>>> door1.__dict__{'number': 1, 'status': 'closed'}>>> door1.colour is Door.colourTrue>>> door1.open is Door.openFalse>>> Door.__dict__['open']<function Door.open at 0xb68604ac>>>> Door.open<unbound method Door.open>>>> door1.open<bound method Door.open of <__main__.Door object at 0xb67e162c>>

What about methods?

Page 70: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.open()Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: open() missing 1 required positional argument: 'self'

From functions to bound methods

Page 71: Dive into Object-oriented Python

Python

2.x

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.open()Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: unbound method open() must be called with Door instanceas first argument (got nothing instead)

From functions to bound methods

Page 72: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.open()Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: open() missing 1 required positional argument: 'self'>>> Door.open(door1)>>> door1.status'open'

From functions to bound methods

Page 73: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.open()Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: open() missing 1 required positional argument: 'self'>>> Door.open(door1)>>> door1.status'open'>>> door1.__class__.__dict__['open']<function Door.open at 0xb68604ac>

From functions to bound methods

Page 74: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.open()Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: open() missing 1 required positional argument: 'self'>>> Door.open(door1)>>> door1.status'open'>>> door1.__class__.__dict__['open']<function Door.open at 0xb68604ac>>>> dir(door1.__class__.__dict__['open'])['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

From functions to bound methods

Page 75: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.open()Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: open() missing 1 required positional argument: 'self'>>> Door.open(door1)>>> door1.status'open'>>> door1.__class__.__dict__['open']<function Door.open at 0xb68604ac>>>> dir(door1.__class__.__dict__['open'])['__annotations__', '__call__', '__class__', '__closure__', ...,'__get__',...]>>> door1.__class__.__dict__['open'].__get__<method-wrapper '__get__' of function object at 0xb68604ac>

From functions to bound methods

Page 76: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.open()Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: open() missing 1 required positional argument: 'self'>>> Door.open(door1)>>> door1.status'open'>>> door1.__class__.__dict__['open']<function Door.open at 0xb68604ac>>>> dir(door1.__class__.__dict__['open'])['__annotations__', '__call__', '__class__', '__closure__', ...,'__get__',...]>>> door1.__class__.__dict__['open'].__get__<method-wrapper '__get__' of function object at 0xb68604ac>>>> door1.__class__.__dict__['open'].__get__(door1)<bound method Door.open of <__main__.Door object at 0xb67e162c>>

From functions to bound methods

Page 77: Dive into Object-oriented Python

Python

2.x

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> Door.open()Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: open() missing 1 required positional argument: 'self'>>> Door.open(door1)>>> door1.status'open'>>> door1.__class__.__dict__['open']<function Door.open at 0xb68604ac>>>> dir(door1.__class__.__dict__['open'])['__annotations__', '__call__', '__class__', '__closure__', ...,'__get__',...]>>> door1.__class__.__dict__['open'].__get__<method-wrapper '__get__' of function object at 0xb68604ac>>>> door1.__class__.__dict__['open'].__get__(door1)<bound method ?.open of <__main__.Door instance at 0xb6977aac>>>>> door1.__class__.__dict__['open'].__get__(door1, Door)<bound method Door.open of <__main__.Door object at 0xb73f956c>>

From functions to bound methods

Page 78: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

class Door: colour = 'brown'

def __init__(self, number, status): self.number = number self.status = status

@classmethod def knock(cls): print("Knock!")

def open(self): self.status = 'open'

def close(self): self.status = 'closed'

Class methods

Page 79: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> door1 = Door(1, 'closed')>>> door1.knock()Knock!>>> Door.knock()Knock!

From functions to bound methods

Page 80: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises

1. Modify the Door class adding a class method 'paint' that accepts a 'colour' argument and changes the class attribute 'colour'.

2. Modify the Door class adding both a class method 'paint' and a standard method 'paint'. What happens?

Page 81: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises1. Modify the Door class adding a class method 'paint' thataccepts a 'colour' argument and changes the class attribute 'colour'.

class Door: colour = 'brown'

def __init__(self, number, status): self.number = number self.status = status

@classmethod def paint(cls, colour): cls.colour = colour

def open(self): self.status = 'open'

def close(self): self.status = 'closed'

Page 82: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises2. Modify the Door class adding both a class method 'paint'and a standard method 'paint'. What happens?

class Door: colour = 'brown'

def __init__(self, number, status): self.number = number self.status = status

@classmethod def paint(cls, colour): cls.colour = colour

def paint(self, colour): self.colour = colour

[...]

Page 83: Dive into Object-oriented Python

PART 3

Delegation

Page 84: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Specialization

CatAnimal

Page 85: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Cat has all the features of Animal, Cat has all the features of Animal, i.e. 'moves'i.e. 'moves'

Specialization

CatAnimal

Page 86: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Cat may provide new features, i.e. Cat may provide new features, i.e. 'has whiskers''has whiskers'

Specialization

CatAnimal

Page 87: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Cat performs some or all the tasks performed by Cat performs some or all the tasks performed by Animal in a different way, i.e. 'moves silently'Animal in a different way, i.e. 'moves silently'

Specialization

CatAnimal

Page 88: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Cat implements only 'new' or Cat implements only 'new' or 'changed' features'changed' features

Cat delegates the remaining Cat delegates the remaining features to Animalfeatures to Animal

Delegation

CatAnimal

Page 89: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Composition: 'has'

Car

Engine turn_on()

Wheels steer()

get_color()

Page 90: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Inheritance: 'is'

look()look()

Cat

Animal

look()

mew()

Page 91: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Page 92: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Inheritance

class SecurityDoor(Door): pass

Page 93: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Inheritance

class SecurityDoor(Door): pass

>>> sdoor = SecurityDoor(1, 'closed')

Page 94: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Inheritance

class SecurityDoor(Door): pass

>>> sdoor = SecurityDoor(1, 'closed')>>> SecurityDoor.colour is Door.colourTrue>>> sdoor.colour is Door.colourTrue

Page 95: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Inheritance

class SecurityDoor(Door): pass

>>> sdoor = SecurityDoor(1, 'closed')>>> SecurityDoor.colour is Door.colourTrue>>> sdoor.colour is Door.colourTrue

sdoor.coloursdoor.colour

SecurityDoor.colourSecurityDoor.colour

Door.colourDoor.colour

Page 96: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Inheritance>>> sdoor.__dict__{'number': 1, 'status': 'closed'}

Page 97: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Inheritance>>> sdoor.__dict__{'number': 1, 'status': 'closed'}>>> sdoor.__class__.__dict__mappingproxy({'__doc__': None, '__module__': '__main__'})>>> Door.__dict__mappingproxy({'__dict__': <attribute '__dict__' of 'Door' objects>, 'colour': 'yellow', 'open': <function Door.open at 0xb687e224>, '__init__': <function Door.__init__ at 0xb687e14c>, '__doc__': None, 'close': <function Door.close at 0xb687e1dc>, 'knock': <classmethod object at 0xb67ff6ac>, '__weakref__': <attribute '__weakref__' of 'Door' objects>, '__module__': '__main__', 'paint': <classmethod object at 0xb67ff6ec>})

Page 98: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Inheritance>>> sdoor.__dict__{'number': 1, 'status': 'closed'}>>> sdoor.__class__.__dict__mappingproxy({'__doc__': None, '__module__': '__main__'})>>> Door.__dict__mappingproxy({'__dict__': <attribute '__dict__' of 'Door' objects>, 'colour': 'yellow', 'open': <function Door.open at 0xb687e224>, '__init__': <function Door.__init__ at 0xb687e14c>, '__doc__': None, 'close': <function Door.close at 0xb687e1dc>, 'knock': <classmethod object at 0xb67ff6ac>, '__weakref__': <attribute '__weakref__' of 'Door' objects>, '__module__': '__main__', 'paint': <classmethod object at 0xb67ff6ec>})>>> SecurityDoor.__bases__(<class '__main__.Door'>,)

Page 99: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Inheritance>>> sdoor.__dict__{'number': 1, 'status': 'closed'}>>> sdoor.__class__.__dict__mappingproxy({'__doc__': None, '__module__': '__main__'})>>> Door.__dict__mappingproxy({'__dict__': <attribute '__dict__' of 'Door' objects>, 'colour': 'yellow', 'open': <function Door.open at 0xb687e224>, '__init__': <function Door.__init__ at 0xb687e14c>, '__doc__': None, 'close': <function Door.close at 0xb687e1dc>, 'knock': <classmethod object at 0xb67ff6ac>, '__weakref__': <attribute '__weakref__' of 'Door' objects>, '__module__': '__main__', 'paint': <classmethod object at 0xb67ff6ec>})>>> SecurityDoor.__bases__(<class '__main__.Door'>,)>>> sdoor.knock<bound method type.knock of <class '__main__.SecurityDoor'>>>>> sdoor.__class__.__bases__[0].__dict__['knock'].__get__(sdoor)<bound method type.knock of <class '__main__.SecurityDoor'>>

Page 100: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Overriding

class SecurityDoor(Door): colour = 'grey' locked = True

def open(self): if not self.locked: self.status = 'open'

Page 101: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Overriding

class SecurityDoor(Door): colour = 'grey' locked = True

def open(self): if not self.locked: self.status = 'open'

>>> SecurityDoor.__dict__mappingproxy({'__doc__': None, '__module__': '__main__', 'open': <function SecurityDoor.open at 0xb6fcf89c>, 'colour': 'grey', 'locked': True})

Page 102: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises

1. Modify the SecurityDoor class adding a custom close_and_lock() method that changes status to 'closed' and locked to True. Test it.

2. Modify the SecurityDoor class adding a custom close() method that accepts a locked flag (with default).

3. Modify the SecurityDoor class adding a custom __init__() method that sets self.locked.

Page 103: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises1. Modify the SecurityDoor class adding a customclose_and_lock() method that changes status to 'closed' and locked to True. Test it.

class SecurityDoor(Door): colour = 'grey' locked = False

def open(self): if not self.locked: self.status = 'open'

def close_and_lock(self): self.status = 'closed' self.locked = True

Page 104: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises2. Modify the SecurityDoor class adding a custom close()method that accepts a locked flag (with default).

class SecurityDoor(Door): colour = 'grey' locked = False

def open(self): if not self.locked: self.status = 'open'

def close(self, locked=False): self.status = 'closed' self.locked = locked

Page 105: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises3. Modify the SecurityDoor class adding a custom __init__() method that sets self.locked.

class SecurityDoor(Door): colour = 'grey'

def __init__(self, number, status, locked=False): self.number = number self.status = status self.locked = locked

def open(self): if not self.locked: self.status = 'open'

Page 106: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Overriding

class SecurityDoor(Door): colour = 'grey'

def __init__(self, number, status, locked=True): Door.__init__(self, number, status) self.locked = locked

def open(self): if self.locked: return Door.open(self)

Page 107: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Overriding

class SecurityDoor(Door): colour = 'grey'

def __init__(self, number, status, locked=True): Door.__init__(self, number, status) self.locked = locked

def open(self): if self.locked: return Door.open(self)

>>> sdoor = SecurityDoor(1, 'closed')

Page 108: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Overriding

class SecurityDoor(Door): colour = 'grey'

def __init__(self, number, status, locked=True): Door.__init__(self, number, status) self.locked = locked

def open(self): if self.locked: return Door.open(self)

>>> sdoor = SecurityDoor(1, 'closed')>>> sdoor.open()>>> sdoor.status'closed'

Page 109: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Overriding

class SecurityDoor(Door): colour = 'grey'

def __init__(self, number, status, locked=True): Door.__init__(self, number, status) self.locked = locked

def open(self): if self.locked: return Door.open(self)

>>> sdoor = SecurityDoor(1, 'closed')>>> sdoor.open()>>> sdoor.status'closed'>>> sdoor.locked = False>>> sdoor.open()>>> sdoor.status'open'

Page 110: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Avoid strong coupling

class SecurityDoor(Door): colour = 'grey'

def __init__(self, number, status, locked=True): super().__init__(number, status) self.locked = locked

def open(self): if self.locked: return super().open()

Page 111: Dive into Object-oriented Python

Python

2.x

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Avoid strong coupling

class SecurityDoor(Door): colour = 'grey'

def __init__(self, number, status, locked=True): super(SecurityDoor, self).__init__(number, status) self.locked = locked

def open(self): if self.locked: return super(SecurityDoor, self).open()

Page 112: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

class SecurityDoor: colour = 'grey'

def __init__(self, number, status, locked=True): self.door = Door(number, status) self.locked = locked

def open(self): if self.locked: return self.door.open()

def close(self): self.door.close()

Composition

Page 113: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

class SecurityDoor: colour = 'grey'

def __init__(self, number, status, locked=True): self.door = Door(number, status) self.locked = locked

def open(self): if self.locked: return self.door.open()

def close(self): self.door.close()

>>> sdoor = SecurityDoor(1, 'closed')>>> sdoor.statusTraceback (most recent call last): File "<stdin>", line 1, in <module>AttributeError: 'SecurityDorr' object has no attribute 'status'

Composition

Page 114: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

class SecurityDoor: colour = 'grey'

def __init__(self, number, status, locked=True): self.door = Door(number, status) self.locked = locked

def open(self): if self.locked: return self.door.open()

def close(self): self.door.close()

def get_status(self): return self.door.status status = property(get_status)

>>> sdoor = SecurityDoor(1, 'closed')>>> sdoor.status'closed'

Composition

Page 115: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Python magic to the rescue

class SecurityDoor: colour = 'grey'

def __init__(self, number, status, locked=True): self.door = Door(number, status) self.locked = locked

def open(self): if self.locked: return self.door.open()

def close(self): self.door.close()

def __getattr__(self, attr): return getattr(self.door, attr)

>>> sdoor = SecurityDoor(1, 'closed')>>> sdoor.status'closed'

Page 116: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Python magic to the rescue

class SecurityDoor: colour = 'grey'

def __init__(self, number, status, locked=True): self.door = Door(number, status) self.locked = locked

def open(self): if self.locked: return self.door.open()

#def close(self): # self.door.close()

def __getattr__(self, attr): return getattr(self.door, attr)

Page 117: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

class ComposedDoor: def __init__(self, number, status): self.door = Door(number, status)

def __getattr__(self, attr): return getattr(self.door, attr)

Composed inheritance?

Page 118: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises

1. Modify the SecurityDoor class adding a custom close_and_lock() method. Use super(). Try and implement it with composition.

2. Modify the SecurityDoor class adding a custom close() method that accepts a locked flag (with default). Use super(). Try and implement it with composition.

Page 119: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises1. Modify the SecurityDoor class adding a customclose_and_lock() method. Use super(). Try and implement it with composition.

class SecurityDoor(Door): colour = 'grey'

def __init__(self, number, status, locked=False): super().__init__(number, status) self.locked = locked

def open(self): if self.locked: return super().open()

def close_and_lock(self): super().close() self.locked = True

Page 120: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises1. Modify the SecurityDoor class adding a customclose_and_lock() method. Use super(). Try and implement it with composition.

class SecurityDoor: colour = 'grey'

def __init__(self, number, status, locked=False): self.door = Door(number, status) self.locked = locked

def open(self): if self.locked: return self.door.open()

def __getattr__(self, attr): return getattr(self.door, attr)

def close_and_lock(self): self.door.close() self.locked = True

Page 121: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises2. Modify the SecurityDoor class adding a custom close()method that accepts a locked flag (with default). Use super().Try and implement it with composition.

class SecurityDoor(Door): colour = 'grey'

def __init__(self, number, status, locked=False): super().__init__(number, status) self.locked = locked

def open(self): if self.locked: return super().open()

def close(self, locked=False): super().close() self.locked = locked

Page 122: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises2. Modify the SecurityDoor class adding a custom close()method that accepts a locked flag (with default). Use super().Try and implement it with composition.

class SecurityDoor: colour = 'grey'

def __init__(self, number, status, locked=False): self.door = Door(number, status) self.locked = locked

def open(self): if self.locked: return self.door.open()

def __getattr__(self, attr): return getattr(self.door, attr)

def close(self, locked=False): self.door.close() self.locked = locked

Page 123: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

getattr()

>>> l = [1,2,3]>>> dir(l)['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

Page 124: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

getattr()

>>> l = [1,2,3]>>> dir(l)['__add__', '__class__', '__contains__', '__delattr__', ..., 'append', 'clear', 'copy', ...]>>> l.append<built-in method append of list object at 0xb70a2c2c>

Page 125: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

getattr()

>>> l = [1,2,3]>>> dir(l)['__add__', '__class__', '__contains__', '__delattr__', ..., 'append', 'clear', 'copy', ...]>>> l.append<built-in method append of list object at 0xb70a2c2c>>>> a = l.append>>> a<built-in method append of list object at 0xb70a2c2c>

Page 126: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

getattr()

>>> l = [1,2,3]>>> dir(l)['__add__', '__class__', '__contains__', '__delattr__', ..., 'append', 'clear', 'copy', ...]>>> l.append<built-in method append of list object at 0xb70a2c2c>>>> a = l.append>>> a<built-in method append of list object at 0xb70a2c2c>>>> b = getattr(l, 'append')>>> b<built-in method append of list object at 0xb70a2c2c>

Page 127: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

getattr()

>>> l = [1,2,3]>>> dir(l)['__add__', '__class__', '__contains__', '__delattr__', ..., 'append', 'clear', 'copy', ...]>>> l.append<built-in method append of list object at 0xb70a2c2c>>>> a = l.append>>> a<built-in method append of list object at 0xb70a2c2c>>>> b = getattr(l, 'append')>>> b<built-in method append of list object at 0xb70a2c2c>>>> a == bTrue>>> a is bFalse

Page 128: Dive into Object-oriented Python

PART 4

Polymorphism

Page 129: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

References

>>> a = 5>>> a5

Page 130: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

References

>>> a = 5>>> a5>>> type(a)<class 'int'>>>> hex(id(a))'0x83fe540'

Page 131: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

References

>>> a = 5>>> a5>>> type(a)<class 'int'>>>> hex(id(a))'0x83fe540'>>> a = 'five'>>> a'five'

Page 132: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

References

>>> a = 5>>> a5>>> type(a)<class 'int'>>>> hex(id(a))'0x83fe540'>>> a = 'five'>>> a'five'>>> type(a)<class 'str'>>>> hex(id(a))'0xb70d6560'

Page 133: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

References

>>> a = 5>>> a5>>> type(a)<class 'int'>>>> hex(id(a))'0x83fe540'>>> a = 'five'>>> a'five'>>> type(a)<class 'str'>>>> hex(id(a))'0xb70d6560'

StrongStrong type system: every type system: every variable has a typevariable has a type

Page 134: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

References

>>> a = 5>>> a5>>> type(a)<class 'int'>>>> hex(id(a))'0x83fe540'>>> a = 'five'>>> a'five'>>> type(a)<class 'str'>>>> hex(id(a))'0xb70d6560'

DynamicDynamic type system: the type type system: the type changes with the contentchanges with the content

Page 135: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Every variable is a reference

def echo(a): return a

Page 136: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Every variable is a reference

def echo(a): return a

>>> echo(5)5>>> echo('five')'five'

Page 137: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> 5 + 611

What is polymorphism?

Page 138: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> 5 + 611>>> 5.5 + 6.612.1

What is polymorphism?

Page 139: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> 5 + 611>>> 5.5 + 6.612.1>>> "just a" + " string"'just a string'

What is polymorphism?

Page 140: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> 5 + 611>>> 5.5 + 6.612.1>>> "just a" + " string"'just a string'>>> [1,2,3] + [4,5,6][1, 2, 3, 4, 5, 6]>>> (1,2,3) + (4,5,6)(1, 2, 3, 4, 5, 6)

What is polymorphism?

Page 141: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> 5 + 611>>> 5.5 + 6.612.1>>> "just a" + " string"'just a string'>>> [1,2,3] + [4,5,6][1, 2, 3, 4, 5, 6]>>> (1,2,3) + (4,5,6)(1, 2, 3, 4, 5, 6)>>> {'a':4, 'b':5} + {'c':7}Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: unsupported operand type(s) for +: 'dict' and 'dict'

What is polymorphism?

Page 142: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> s = "Just a sentence">>> len(s)15>>> l = [1, 2, 3]>>> len(l)3>>> d = {'a': 1, 'b': 2}>>> len(d)2

What is polymorphism?

Page 143: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> s = "Just a sentence">>> len(s)15>>> l = [1, 2, 3]>>> len(l)3>>> d = {'a': 1, 'b': 2}>>> len(d)2>>> i = 5>>> len(i)Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: object of type 'int' has no len()

What is polymorphism?

Page 144: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> s.__len__()15>>> l.__len__()3>>> d.__len__()2

What is polymorphism?

Page 145: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> s.__len__()15>>> l.__len__()3>>> d.__len__()2>>> i.__len__()Traceback (most recent call last): File "<stdin>", line 1, in <module>AttributeError: 'int' objecthas no attribute '__len__'

What is polymorphism?

Page 146: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> [1,2,3].__add__([4,5,6])[1, 2, 3, 4, 5, 6]

Polymorphism is based on delegation

Page 147: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> [1,2,3].__add__([4,5,6])[1, 2, 3, 4, 5, 6]>>> dir([1,2,3])['__add__', '__class__', '__contains__', ...]

Polymorphism is based on delegation

Page 148: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> [1,2,3].__add__([4,5,6])[1, 2, 3, 4, 5, 6]>>> dir([1,2,3])['__add__', '__class__', '__contains__', ...]>>> 1 in [1,2,3]True>>> [1,2,3].__contains__(1)True

Polymorphism is based on delegation

Page 149: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> [1,2,3].__add__([4,5,6])[1, 2, 3, 4, 5, 6]>>> dir([1,2,3])['__add__', '__class__', '__contains__', ...]>>> 1 in [1,2,3]True>>> [1,2,3].__contains__(1)True>>> 6 in [1,2,3]False>>> [1,2,3].__contains__(6)False

Polymorphism is based on delegation

Page 150: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

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

Polymorphism is based on delegation

Page 151: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

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

>>> sum(5,6)11>>> sum("Being ", "polymorphic")'Being polymorphic'>>> sum([1,2,3], [4,5,6])[1, 2, 3, 4, 5, 6]

Polymorphism is based on delegation

Page 152: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

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

>>> sum(5,6)11>>> sum("Being ", "polymorphic")'Being polymorphic'>>> sum([1,2,3], [4,5,6])[1, 2, 3, 4, 5, 6]>>> sum([1,2,3], 8)Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in sumTypeError: can only concatenate list (not "int") to list

Polymorphism is based on delegation

Page 153: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises

1. Create a class that contains an integer as self.value and with a __len__ method that returns the number of digits of the integer. Does len() work for instances of this class?

2. Add a __contains__() method that returns True if self.value contains the given digit. Does 'in' work for this type?

3. Try str() on an instance of your class. What happens? How can you return a better string representation (e.g. to show the actual value)?

Page 154: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises1. Create a class that contains an integer as self.value andwith a __len__ method that returns the number of digits of the integer. Does len() work for instances of this class?

class CustomInteger: def __init__(self, value): self.value = value

def __len__(self): return len(str(self.value))

Page 155: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises2. Add a __contains__() method that returns True if self.value contains the given digit. Does 'in' work for this type?

class CustomInteger: def __init__(self, value): self.value = value

def __len__(self): return len(str(self.value))

def __contains__(self, digit): return str(digit) in str(self.value)

Page 156: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises3. Try str() on an instance of your class. What happens? Howcan you return a better string representation (e.g. to show the actual value)?

class CustomInteger: def __init__(self, value): self.value = value

def __len__(self): return len(str(self.value))

def __contains__(self, digit): return str(digit) in str(self.value)

def __str__(self): return super().__str__() + ' [{}]'.format(self.value)

Page 157: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

class Room: def __init__(self, door): self.door = door

def open(self): self.door.open()

def close(self): self.door.close()

def is_open(self): return self.door.is_open()

Polymorphism in action

Page 158: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

class Door: def __init__(self): self.status = "closed"

def open(self): self.status = "open"

def close(self): self.status = "closed"

def is_open(self): return self.status == "open"

Polymorphism in action

Page 159: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

class BooleanDoor: def __init__(self): self.status = True

def open(self): self.status = True

def close(self): self.status = False

def is_open(self): return self.status

Polymorphism in action

Page 160: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> door = Door()>>> bool_door = BooleanDoor()

Polymorphism in action

Page 161: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> door = Door()>>> bool_door = BooleanDoor()>>> room = Room(door)>>> bool_room = Room(bool_door)

Polymorphism in action

Page 162: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> door = Door()>>> bool_door = BooleanDoor()>>> room = Room(door)>>> bool_room = Room(bool_door)>>> room.open()>>> room.is_open()True>>> room.close()>>> room.is_open()False

Polymorphism in action

Page 163: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

>>> door = Door()>>> bool_door = BooleanDoor()>>> room = Room(door)>>> bool_room = Room(bool_door)>>> room.open()>>> room.is_open()True>>> room.close()>>> room.is_open()False>>> bool_room.open()>>> bool_room.is_open()True>>> bool_room.close()>>> bool_room.is_open()False

Polymorphism in action

Page 164: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises

1. Modify the Room, the Door and the BooleanDoor classes to add a toggle() method that changes open status to closed and vice versa.

2. Change the Room class such that it accepts a class instead of an instance. How do you manage it into __init__()? Does it still work?

3. Create a PetDoor object that inherits from Door (or BooleanDoor). Add the suitable methods to manage the small pet door. Does the Room work?

4. May you reuse the Door to create the pet door?

Page 165: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises1. Modify the Room, the Door and the BooleanDoor classesto add a toggle() method that changes open status to closedand vice versa.

class Room: def __init__(self, door): self.door = door

def open(self): self.door.open()

def close(self): self.door.close()

def is_open(self): return self.door.is_open()

def toggle(self): if self.door.is_open(): self.door.close() else: self.door.open()

Page 166: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises2. Change the Room class such that it accepts a class insteadof an instance. How do you manage it into __init__()? Does itstill work?

class Room: def __init__(self, door_cls): self.door = door_cls()

def open(self): self.door.open()

def close(self): self.door.close()

def is_open(self): return self.door.is_open()

>>> room = Room(Door)>>> bool_room = Room(BooleanDoor)

Page 167: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises3. Create a PetDoor object that inherits from Door (or BooleanDoor). Add the suitable methods to manage the smallpet door. Does the Room work?

class PetDoor(BooleanDoor): def __init__(self): super().__init__() self.pet_door = "open"

def open_pet_door(self): self.pet_door = "open"

def close_pet_door(self): self.pet_door = "closed"

Page 168: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

Exercises4. May you reuse the Door to create the pet door?

class PetDoor(BooleanDoor): def __init__(self): super().__init__() self.pet_door = BooleanDoor()

def open_pet_door(self): self.pet_door.open()

def close_pet_door(self): self.pet_door.close()

Page 169: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

“Ask for permission” style

if hasattr(someobj, 'open'): [...]else: [...]

It It hashas the attribute the attribute

Page 170: Dive into Object-oriented Python

Dive into Object-oriented Python – lgiordani.com - CC BY-SA 4.0

“Ask for permission” style

try: someobj.open() [...]except AttributeError: [...]

It It behavesbehaves like it has like it has the attributethe attribute

Page 171: Dive into Object-oriented Python

The communityprovided free information and code

Font aswesome iconsby Freepik

CAST

Page 172: Dive into Object-oriented Python

Python 3 OOP serieshttp://lgiordani.com/blog/categories/python3/

Some links about Python OOPhttp://goo.gl/UBdJDT

LINKS

Page 173: Dive into Object-oriented Python