object-oriented python from scratch
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