object-oriented python from scratch

Post on 17-Jul-2015

341 Views

Category:

Technology

15 Downloads

Preview:

Click to see full reader

TRANSCRIPT

OBJECT-ORIENTED PYTHONFrom scratch

Leonardo Giordanilgiordani.comO

OP

I'm a software engineer, interested in operating systems, versioning, Python and software architecture.

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.

about me

The Digital Cat

lgiordani.comhttps://twitter.com/

tw_lgiordanihttps://github.com/

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

LeonardoGiordani

import usersimport talk

assert all([a >= users.beginner for a in talk.attendees])

about_you.py

ABOUT THIS TUTORIAL

This tutorial covers Python 3.Almost all concepts are valid for Python 2.Relevant differences will be highlighted.

Objects and types

Classes and members

Delegation

Polymorphism

Metaclasses

3

https://github.com/lgiordani/oopy

Code available as IPython Notebooks

PART 1

Objects and types

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-2 27

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

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

avg(data)92.83333333333333

Plain old procedurespart1/01.py

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-3 27

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

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

avg(data)92.83333333333333

Very simple data:Very simple data:a sequence of numbersa sequence of numbers

This returns new dataThis returns new data

part1/01.py

Source data enters hereSource data enters here

Plain old procedures

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-4 27

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

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

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

part1/02.py Procedures can modify data

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-5 27

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'

part1/03.py Things can get complicated

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-6 27

Same “action”Same “action”

You must useYou must usethe right functionthe right function

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']

part1/03.py Things can get complicated

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-7 27

BehavesBehaveslike a ducklike a duck

Behavioural meaning

The meaning of the word 'type'

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-8 27

DissectionDissectionrevealsreveals

the the truthtruth

Structural meaning

The meaning of the word 'type'

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-9 27

The behavioural meaning is important

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-10 27

Duck typing: make it behave like a duck

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-11 27

Duck typing joke #1

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-12 27

Duck typing joke #2

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-13 27

The meaning of the word 'class'

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-14 27

The meaning of the word 'instance'

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-15 27

a = 6a6

type(a)<class 'int'>

You already used classes

Python

2.x

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-16 27

You already used classes

a = 6a6

type(a)<type 'int'>

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-17 27

The first classpart1/04.py

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'

Python

2.x

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-18 27

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'

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-19 27

The first classpart1/04.py

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'

The 'class' keyword defines the classThe 'class' keyword defines the class

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-20 27

The first classpart1/04.py

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'

Everything under the 'class' Everything under the 'class' keyword is part of the classkeyword is part of the class

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-21 27

The first classpart1/04.py

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'

MethodMethod

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-22 27

The first classpart1/04.py

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'

AttributesAttributes

Constructor (part of)Constructor (part of)

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-23 27

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'

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-24 27

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'

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-25 27

door1 = Door(1, 'closed')type(door1)<class '__main__.Door'>door1.number1door1.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'

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-26 27

door1 = Door(1, 'closed')type(door1)<class '__main__.Door'>door1.number1door1.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'

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0I-27 27

door1 = Door(1, 'closed')type(door1)<class '__main__.Door'>door1.number1door1.status'closed'door1.open()door1.number1door1.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'

PART 2

Classes and members

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-2 42

Everything is an object

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-3 42

Everything is an object

a = 1type(a)<class 'int'>type(int)<class 'type'> The type of an object is The type of an object is

an object itselfan object itself

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-4 42

Where is the class of an object?

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-5 42

Where is the class of an object?

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-6 42

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'

The class is not a mere concept! The class is not a mere concept! It is an object in the system.It is an object in the system.

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-7 42

Class attributespart2/01.py

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'

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-8 42

part2/01.py

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'

No 'self' hereNo 'self' here

Class attributes

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-9 42

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

Class attributes

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-10 42

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

Class attributes

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-11 42

Door.colour = 'white'

Class attributes

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-12 42

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

Class attributes

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-13 42

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-14 42

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-15 42

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-16 42

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-17 42

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-18 42

Door

door1 door2

__getattribute__()__getattribute__()

Let's dive into attribute resolution

door1.colour

Door.colour

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-19 42

Let's dive into attribute resolution

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-20 42

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'

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-21 42

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'

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-22 42

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'

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-23 42

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?

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-24 42

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.colourTruedoor1.open is Door.openFalse

What about methods?

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-25 42

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.colourTruedoor1.open is Door.openFalseDoor.__dict__['open']<function Door.open at 0xb68604ac>Door.open<function Door.open at 0xb68604ac>

What about methods?

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-26 42

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.colourTruedoor1.open is Door.openFalseDoor.__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?

Python

2.x

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-27 42

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.colourTruedoor1.open is Door.openFalseDoor.__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?

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-28 42

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

Python

2.x

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-29 42

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-30 42

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-31 42

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-32 42

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-33 42

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-34 42

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

Python

2.x

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-35 42

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-36 42

part2/02.py

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-37 42

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

From functions to bound methods

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-38 42

part2/03.py

class Door: colour = 'brown'

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

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

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

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

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

Class methods

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-39 42

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

Class methods

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-40 42

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

Class methods

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-41 42

Door.paint('white')Door.colour'white'door1.colour'white'door2.colour'white'

Class methods

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0II-42 42

Door.paint('white')Door.colour'white'door1.colour'white'door2.colour'white'door1.paint('yellow')Door.colour'yellow'door1.colour'yellow'door2.colour'yellow'

Class methods

PART 3

Delegation

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-2 36

Specialization

CatAnimal

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-3 36

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

Specialization

CatAnimal

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-4 36

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

Specialization

CatAnimal

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-5 36

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

Specialization

CatAnimal

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-6 36

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-7 36

Composition: 'has'

Car

Engine turn_on()

Wheels steer()

get_color()

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-8 36

Inheritance: 'is'

look()look()

Cat

Animal

look()

mew()

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-9 36

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-10 36

Inheritancepart3/01.py

class SecurityDoor(Door): pass

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-11 36

Inheritance

class SecurityDoor(Door): pass

sdoor = SecurityDoor(1, 'closed')

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-12 36

Inheritance

class SecurityDoor(Door): pass

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-13 36

Inheritance

class SecurityDoor(Door): pass

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

sdoor.coloursdoor.colour

SecurityDoor.colourSecurityDoor.colour

Door.colourDoor.colour

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-14 36

Inheritancesdoor.__dict__{'number': 1, 'status': 'closed'}

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-15 36

Inheritancesdoor.__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>})

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-16 36

Inheritancesdoor.__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'>,)

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-17 36

Inheritancesdoor.__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'>>

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-18 36

Overridingpart3/02.py

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

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-19 36

Overridingpart3/02.py

Overriding blocks implicit Overriding blocks implicit delegationdelegation

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})

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-20 36

Overridingpart3/03.py

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

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-21 36

Overridingpart3/03.py

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

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

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-22 36

Overridingpart3/03.py

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

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

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-23 36

Overridingpart3/03.py

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

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

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-24 36

Avoid strong couplingpart3/04.py

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

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

Python

2.x

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-25 36

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

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

Avoid strong coupling

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-26 36

class SecurityDoor: colour = 'grey' locked = True

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

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

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

Compositionpart3/05.py

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-27 36

class SecurityDoor: colour = 'grey' locked = True

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

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'

Compositionpart3/05.py

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-28 36

class SecurityDoor: colour = 'grey' locked = True

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

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-29 36

Python magic to the rescue

class SecurityDoor: colour = 'grey' locked = True

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

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'

part3/06.py

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-30 36

Python magic to the rescue

class SecurityDoor: colour = 'grey' locked = True

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

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)

part3/07.py

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-31 36

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

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

Composed inheritance?part3/08.py

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-32 36

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']

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-33 36

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>

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-34 36

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.appenda<built-in method append of list object at 0xb70a2c2c>

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-35 36

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.appenda<built-in method append of list object at 0xb70a2c2c>b = getattr(l, 'append')b<built-in method append of list object at 0xb70a2c2c>

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0III-36 36

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.appenda<built-in method append of list object at 0xb70a2c2c>b = getattr(l, 'append')b<built-in method append of list object at 0xb70a2c2c>a == bTruea is bFalse

PART 4

Polymorphism

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-2 34

References

a = 5a5

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-3 34

References

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-4 34

References

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-5 34

References

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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-6 34

References

a = 5a5type(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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-7 34

References

a = 5a5type(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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-8 34

Every variable is a reference

def echo(a): return a

part4/01.py

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-9 34

Every variable is a reference

def echo(a): return a

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

part4/01.py

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-10 34

5 + 611

What is polymorphism?

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-11 34

5 + 6115.5 + 6.612.1

What is polymorphism?

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-12 34

5 + 6115.5 + 6.612.1"just a" + " string"'just a string'

What is polymorphism?

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-13 34

5 + 6115.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?

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-14 34

5 + 6115.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?

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-15 34

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

What is polymorphism?

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-16 34

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

What is polymorphism?

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-17 34

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

What is polymorphism?

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-18 34

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

What is polymorphism?

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-19 34

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

Polymorphism is based on delegation

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-20 34

[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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-21 34

[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

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-22 34

[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)True6 in [1,2,3]False[1,2,3].__contains__(6)False

Polymorphism is based on delegation

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-23 34

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

Polymorphism is based on delegationpart4/02.py

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-24 34

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

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

Polymorphism is based on delegationpart4/02.py

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-25 34

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

sum(5,6)11sum("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 delegationpart4/02.py

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-26 34

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 actionpart4/03.py

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-27 34

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 actionpart4/03.py

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-28 34

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 actionpart4/03.py

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-29 34

door = Door()bool_door = BooleanDoor()

Polymorphism in action

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-30 34

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

Polymorphism in action

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-31 34

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

Polymorphism in action

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-32 34

door = Door()bool_door = BooleanDoor()room = Room(door)bool_room = Room(bool_door)room.open()room.is_open()Trueroom.close()room.is_open()Falsebool_room.open()bool_room.is_open()Truebool_room.close()bool_room.is_open()False

Polymorphism in action

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-33 34

“Ask for permission” style

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

It It hashas the attribute the attribute

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0IV-34 34

“Ask for permission” style

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

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

PART 5

Metaclasses

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0V-2 20

Everything is an object (again)

a = 5type(a)<class 'int'>a.__class__<class 'int'>a.__class__.__bases__(<class 'object'>,)object.__bases__()

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0V-3 20

Everything is an object (again)

a = 5type(a)<class 'int'>a.__class__<class 'int'>a.__class__.__bases__(<class 'object'>,)object.__bases__()

'int' 'int' inherits frominherits from(its base is) 'object'(its base is) 'object'

'a' 'a' is an is an instance ofinstance of

(its type is) 'int' (its type is) 'int'

object

int

a

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0V-4 20

Everything is an object (again)

a = 5type(a)<class 'int'>a.__class__<class 'int'>a.__class__.__bases__(<class 'object'>,)object.__bases__()

InheritanceInheritance: 'int' finds : 'int' finds here attributes and here attributes and

methodsmethods

InstanceInstance: 'a' : 'a' description as a description as a class is hereclass is here

object

int

a

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0V-5 20

Everything is an object (again)

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

object

int

a

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0V-6 20

Everything is an object (again)

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

object

int

a

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0V-7 20

Everything is an object (again)

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

object

a

type

int int

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0V-8 20

Everything is an object (again)

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

object

a

type

int int'int' 'int' inherits inherits

fromfrom(its base is) (its base is)

'object''object'

'int' 'int' is an instance ofis an instance of(its type is) 'type' (its type is) 'type'

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0V-9 20

Everything is an object (again)

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

object

a

type

int int

'int' finds here 'int' finds here attributes and attributes and

methodsmethods

'int' description as a 'int' description as a class is hereclass is here

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0V-10 20

Food for thought

type(object)<class 'type'>type.__bases__(<class 'object'>,)

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0V-11 20

Food for thought

type(object)<class 'type'>type.__bases__(<class 'object'>,)

object

type

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0V-12 20

type(object)<class 'type'>type.__bases__(<class 'object'>,)type(type)<class 'type'>

object

type

Fatality

Python

2.x

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0V-13 20

type(object)<class 'type'>type.__bases__(<class 'object'>,)type(type)<type 'type'>

object

type

Fatality

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0V-14 20

Metaclasses

class MyType(type): pass

class MySpecialClass(metaclass=MyType): pass

part5/01.py

Python

2.x

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0V-15 20

Metaclasses

class MyType(type): pass

class MySpecialClass(object):__metaclass__ = MyType

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0V-16 20

Metaclasses

class MyType(type): pass

class MySpecialClass(metaclass=MyType): pass

msp = MySpecialClass()type(msp)<class '__main__.MySpecialClass'>

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0V-17 20

Metaclasses

class MyType(type): pass

class MySpecialClass(metaclass=MyType): pass

msp = MySpecialClass()type(msp)<class '__main__.MySpecialClass'>type(MySpecialClass)<class '__main__.MyType'>MySpecialClass.__bases__(<class 'object'>,)

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0V-18 20

Metaclasses in action: singletonpart5/02.py

class Singleton(type): instance = None def __call__(cls, *args, **kw): if not cls.instance: cls.instance = super(Singleton, cls).

__call__(*args, **kw) return cls.instance

class ASingleton(metaclass=Singleton): pass

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0V-19 20

Metaclasses in action: singletonpart5/02.py

class Singleton(type): instance = None def __call__(cls, *args, **kw): if not cls.instance: cls.instance = super(Singleton, cls).

__call__(*args, **kw) return cls.instance

class ASingleton(metaclass=Singleton): pass

a = ASingleton()b = ASingleton()

Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0V-20 20

Metaclasses in action: singletonpart5/02.py

class Singleton(type): instance = None def __call__(cls, *args, **kw): if not cls.instance: cls.instance = super(Singleton, cls).

__call__(*args, **kw) return cls.instance

class ASingleton(metaclass=Singleton): pass

a = ASingleton()b = ASingleton()a is bTruehex(id(a))'0xb68030ec'hex(id(b))'0xb68030ec'

A lot of peopleprovided free information and code

Font aswesome iconsby Freepik

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

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

CAST

OBJECT-ORIENTED PYTHONFrom scratch

Leonardo Giordanilgiordani.comO

OP

top related