Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Object-Oriented Python From scratch

Leonardo Giordani
April 08, 2015
570

Object-Oriented Python From scratch

Leonardo Giordani

April 08, 2015
Tweet

Transcript

  1. 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.com https://twitter.com/ tw_lgiordani https://github.com/ lgiordani https://plus.google.com/u/ LeonardoGiordani
  2. 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
  3. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-2 27 data = (13, 63, 5, 378, 58, 40) def avg(d): return sum(d)/len(d) avg(data) 92.83333333333333 Plain old procedures part1/01.py
  4. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-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 numbers a sequence of numbers This returns new data This returns new data part1/01.py Source data enters here Source data enters here Plain old procedures
  5. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-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
  6. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-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
  7. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-6 27 Same “action” Same “action” You must use You must use the right function the 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
  8. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-7 27 Behaves Behaves like a duck like a duck Behavioural meaning The meaning of the word 'type'
  9. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-8 27 Dissection Dissection reveals reveals the the truth truth Structural meaning The meaning of the word 'type'
  10. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-9 27 The behavioural meaning is important
  11. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-10 27 Duck typing: make it behave like a duck
  12. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-15 27 a = 6 a 6 type(a) <class 'int'> You already used classes
  13. Python 2.x Object-oriented Python from scratch – lgiordani.com - CC

    BY-SA 4.0 I-16 27 You already used classes a = 6 a 6 type(a) <type 'int'>
  14. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-17 27 The first class part1/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'
  15. Python 2.x Object-oriented Python from scratch – lgiordani.com - CC

    BY-SA 4.0 I-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'
  16. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-19 27 The first class part1/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 class The 'class' keyword defines the class
  17. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-20 27 The first class part1/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 class keyword is part of the class
  18. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-21 27 The first class part1/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' Method Method
  19. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-22 27 The first class part1/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' Attributes Attributes Constructor (part of) Constructor (part of)
  20. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-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'
  21. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-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'
  22. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-25 27 door1 = Door(1, 'closed') type(door1) <class '__main__.Door'> door1.number 1 door1.status 'closed' The first class class Door: def __init__(self, number, status): self.number = number self.status = status def open(self): self.status = 'open' def close(self): self.status = 'closed'
  23. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-26 27 door1 = Door(1, 'closed') type(door1) <class '__main__.Door'> door1.number 1 door1.status 'closed' door1.open() The first class class Door: def __init__(self, number, status): self.number = number self.status = status def open(self): self.status = 'open' def close(self): self.status = 'closed'
  24. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    I-27 27 door1 = Door(1, 'closed') type(door1) <class '__main__.Door'> door1.number 1 door1.status 'closed' door1.open() door1.number 1 door1.status 'open' The first class class Door: def __init__(self, number, status): self.number = number self.status = status def open(self): self.status = 'open' def close(self): self.status = 'closed'
  25. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-2 42 Everything is an object a = 1 type(a) <class 'int'>
  26. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-3 42 Everything is an object a = 1 type(a) <class 'int'> type(int) <class 'type'> The type of an object is The type of an object is an object itself an object itself
  27. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-4 42 Where is the class of an object? door1 = Door(1, 'closed') door2 = Door(1, 'closed')
  28. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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'
  29. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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.
  30. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-7 42 Class attributes 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'
  31. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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' here No 'self' here Class attributes
  32. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-9 42 door1 = Door(1, 'closed') door2 = Door(2, 'closed') Class attributes
  33. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-10 42 door1 = Door(1, 'closed') door2 = Door(2, 'closed') Door.colour 'brown' door1.colour 'brown' door2.colour 'brown' Class attributes
  34. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-11 42 Door.colour = 'white' Class attributes
  35. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-12 42 Door.colour = 'white' Door.colour 'white' door1.colour 'white' door2.colour 'white' Class attributes
  36. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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
  37. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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
  38. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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
  39. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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
  40. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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.colour True Class attributes
  41. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-18 42 Door door1 door2 __getattribute__() __getattribute__() Let's dive into attribute resolution door1.colour Door.colour
  42. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-19 42 Let's dive into attribute resolution door1 = Door(1, 'closed') door1.colour = 'white' door1.__dict__['colour'] 'white' door1.__class__.__dict__['colour'] 'brown'
  43. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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'
  44. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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'
  45. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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'
  46. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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.colour True What about methods?
  47. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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.colour True door1.open is Door.open False What about methods?
  48. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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.colour True door1.open is Door.open False Door.__dict__['open'] <function Door.open at 0xb68604ac> Door.open <function Door.open at 0xb68604ac> What about methods?
  49. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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.colour True door1.open is Door.open False Door.__dict__['open'] <function Door.open at 0xb68604ac> Door.open <function Door.open at 0xb68604ac> door1.open <bound method Door.open of <__main__.Door object at 0xb67e162c>> What about methods?
  50. Python 2.x Object-oriented Python from scratch – lgiordani.com - CC

    BY-SA 4.0 II-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.colour True door1.open is Door.open False Door.__dict__['open'] <function Door.open at 0xb68604ac> Door.open <unbound method Door.open> door1.open <bound method Door.open of <__main__.Door object at 0xb67e162c>> What about methods?
  51. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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
  52. Python 2.x Object-oriented Python from scratch – lgiordani.com - CC

    BY-SA 4.0 II-29 42 Door.open() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unbound method open() must be called with Door instance as first argument (got nothing instead) From functions to bound methods
  53. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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
  54. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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
  55. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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
  56. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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
  57. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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
  58. Python 2.x Object-oriented Python from scratch – lgiordani.com - CC

    BY-SA 4.0 II-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
  59. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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
  60. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-37 42 door1 = Door(1, 'closed') door1.knock() Knock! Door.knock() Knock! From functions to bound methods
  61. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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
  62. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-39 42 door1 = Door(1, 'closed') door2 = Door(2, 'closed') Class methods
  63. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-40 42 door1 = Door(1, 'closed') door2 = Door(2, 'closed') Door.colour 'brown' door1.colour 'brown' door2.colour 'brown' Class methods
  64. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-41 42 Door.paint('white') Door.colour 'white' door1.colour 'white' door2.colour 'white' Class methods
  65. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    II-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
  66. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-3 36 Cat has all the features of Cat has all the features of Animal, i.e. 'moves' Animal, i.e. 'moves' Specialization Cat Animal
  67. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-4 36 Cat can provide new features, i.e. Cat can provide new features, i.e. 'has whiskers' 'has whiskers' Specialization Cat Animal
  68. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-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 Cat Animal
  69. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-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 Animal features to Animal Delegation Cat Animal
  70. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-7 36 Composition: 'has' Car Engine turn_on() Wheels steer() get_color()
  71. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-8 36 Inheritance: 'is' look() look() Cat Animal look() mew()
  72. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-10 36 Inheritance part3/01.py class SecurityDoor(Door): pass
  73. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-11 36 Inheritance class SecurityDoor(Door): pass sdoor = SecurityDoor(1, 'closed')
  74. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-12 36 Inheritance class SecurityDoor(Door): pass sdoor = SecurityDoor(1, 'closed') SecurityDoor.colour is Door.colour True sdoor.colour is Door.colour True
  75. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-13 36 Inheritance class SecurityDoor(Door): pass sdoor = SecurityDoor(1, 'closed') SecurityDoor.colour is Door.colour True sdoor.colour is Door.colour True sdoor.colour sdoor.colour SecurityDoor.colour SecurityDoor.colour Door.colour Door.colour
  76. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-14 36 Inheritance sdoor.__dict__ {'number': 1, 'status': 'closed'}
  77. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-15 36 Inheritance sdoor.__dict__ {'number': 1, 'status': 'closed'} sdoor.__class__.__dict__ mappingproxy({'__doc__': None, '__module__': '__main__'}) Door.__dict__ mappingproxy({'__dict__': <attribute '__dict__' of 'Door' objects>, 'colour': 'yellow', 'open': <function Door.open at 0xb687e224>, '__init__': <function Door.__init__ at 0xb687e14c>, '__doc__': None, 'close': <function Door.close at 0xb687e1dc>, 'knock': <classmethod object at 0xb67ff6ac>, '__weakref__': <attribute '__weakref__' of 'Door' objects>, '__module__': '__main__', 'paint': <classmethod object at 0xb67ff6ec>})
  78. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-16 36 Inheritance sdoor.__dict__ {'number': 1, 'status': 'closed'} sdoor.__class__.__dict__ mappingproxy({'__doc__': None, '__module__': '__main__'}) Door.__dict__ mappingproxy({'__dict__': <attribute '__dict__' of 'Door' objects>, 'colour': 'yellow', 'open': <function Door.open at 0xb687e224>, '__init__': <function Door.__init__ at 0xb687e14c>, '__doc__': None, 'close': <function Door.close at 0xb687e1dc>, 'knock': <classmethod object at 0xb67ff6ac>, '__weakref__': <attribute '__weakref__' of 'Door' objects>, '__module__': '__main__', 'paint': <classmethod object at 0xb67ff6ec>}) SecurityDoor.__bases__ (<class '__main__.Door'>,)
  79. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-17 36 Inheritance sdoor.__dict__ {'number': 1, 'status': 'closed'} sdoor.__class__.__dict__ mappingproxy({'__doc__': None, '__module__': '__main__'}) Door.__dict__ mappingproxy({'__dict__': <attribute '__dict__' of 'Door' objects>, 'colour': 'yellow', 'open': <function Door.open at 0xb687e224>, '__init__': <function Door.__init__ at 0xb687e14c>, '__doc__': None, 'close': <function Door.close at 0xb687e1dc>, 'knock': <classmethod object at 0xb67ff6ac>, '__weakref__': <attribute '__weakref__' of 'Door' objects>, '__module__': '__main__', 'paint': <classmethod object at 0xb67ff6ec>}) SecurityDoor.__bases__ (<class '__main__.Door'>,) sdoor.knock <bound method type.knock of <class '__main__.SecurityDoor'>> sdoor.__class__.__bases__[0].__dict__['knock'].__get__(sdoor) <bound method type.knock of <class '__main__.SecurityDoor'>>
  80. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-18 36 Overriding part3/02.py class SecurityDoor(Door): colour = 'grey' locked = True def open(self): if not self.locked: self.status = 'open'
  81. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-19 36 Overriding part3/02.py Overriding blocks implicit Overriding blocks implicit delegation delegation 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})
  82. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-20 36 Overriding part3/03.py class SecurityDoor(Door): colour = 'grey' locked = True def open(self): if self.locked: return Door.open(self)
  83. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-21 36 Overriding part3/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'
  84. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-22 36 Overriding part3/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'
  85. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-23 36 Overriding part3/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 = False sdoor.open() sdoor.status 'open'
  86. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-24 36 Avoid strong coupling part3/04.py class SecurityDoor(Door): colour = 'grey' locked = True def open(self): if self.locked: return super().open()
  87. Python 2.x Object-oriented Python from scratch – lgiordani.com - CC

    BY-SA 4.0 III-25 36 class SecurityDoor(Door): colour = 'grey' locked = True def open(self): if self.locked: return super(SecurityDoor, self).open(self) Avoid strong coupling
  88. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-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() Composition part3/05.py
  89. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-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.status Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'SecurityDorr' object has no attribute 'status' Composition part3/05.py
  90. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-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
  91. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-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
  92. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-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
  93. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-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
  94. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-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']
  95. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-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>
  96. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-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.append a <built-in method append of list object at 0xb70a2c2c>
  97. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-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.append a <built-in method append of list object at 0xb70a2c2c> b = getattr(l, 'append') b <built-in method append of list object at 0xb70a2c2c>
  98. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    III-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.append a <built-in method append of list object at 0xb70a2c2c> b = getattr(l, 'append') b <built-in method append of list object at 0xb70a2c2c> a == b True a is b False
  99. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-3 34 References a = 5 a 5 type(a) <class 'int'> hex(id(a)) '0x83fe540'
  100. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-4 34 References a = 5 a 5 type(a) <class 'int'> hex(id(a)) '0x83fe540' a = 'five' a 'five'
  101. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-5 34 References a = 5 a 5 type(a) <class 'int'> hex(id(a)) '0x83fe540' a = 'five' a 'five' type(a) <class 'str'> hex(id(a)) '0xb70d6560'
  102. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-6 34 References a = 5 a 5 type(a) <class 'int'> hex(id(a)) '0x83fe540' a = 'five' a 'five' type(a) <class 'str'> hex(id(a)) '0xb70d6560' Strong Strong type system: every type system: every variable has a type variable has a type
  103. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-7 34 References a = 5 a 5 type(a) <class 'int'> hex(id(a)) '0x83fe540' a = 'five' a 'five' type(a) <class 'str'> hex(id(a)) '0xb70d6560' Dynamic Dynamic type system: the type type system: the type changes with the content changes with the content
  104. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-8 34 Every variable is a reference def echo(a): return a part4/01.py
  105. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-9 34 Every variable is a reference def echo(a): return a echo(5) 5 echo('five') 'five' part4/01.py
  106. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-11 34 5 + 6 11 5.5 + 6.6 12.1 What is polymorphism?
  107. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-12 34 5 + 6 11 5.5 + 6.6 12.1 "just a" + " string" 'just a string' What is polymorphism?
  108. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-13 34 5 + 6 11 5.5 + 6.6 12.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?
  109. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-14 34 5 + 6 11 5.5 + 6.6 12.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?
  110. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-15 34 s = "Just a sentence" len(s) 15 l = [1, 2, 3] len(l) 3 d = {'a': 1, 'b': 2} len(d) 2 What is polymorphism?
  111. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-16 34 s = "Just a sentence" len(s) 15 l = [1, 2, 3] len(l) 3 d = {'a': 1, 'b': 2} len(d) 2 i = 5 len(i) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: object of type 'int' has no len() What is polymorphism?
  112. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-17 34 s.__len__() 15 l.__len__() 3 d.__len__() 2 What is polymorphism?
  113. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-18 34 s.__len__() 15 l.__len__() 3 d.__len__() 2 i.__len__() Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'int' object has no attribute '__len__' What is polymorphism?
  114. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-19 34 [1,2,3].__add__([4,5,6]) [1, 2, 3, 4, 5, 6] Polymorphism is based on delegation
  115. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-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
  116. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-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
  117. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-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) True 6 in [1,2,3] False [1,2,3].__contains__(6) False Polymorphism is based on delegation
  118. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-23 34 def sum(a, b): return a + b Polymorphism is based on delegation part4/02.py
  119. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-24 34 def sum(a, b): return a + b sum(5,6) 11 sum("Being ", "polymorphic") 'Being polymorphic' sum([1,2,3], [4,5,6]) [1, 2, 3, 4, 5, 6] Polymorphism is based on delegation part4/02.py
  120. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-25 34 def sum(a, b): return a + b sum(5,6) 11 sum("Being ", "polymorphic") 'Being polymorphic' sum([1,2,3], [4,5,6]) [1, 2, 3, 4, 5, 6] sum([1,2,3], 8) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in sum TypeError: can only concatenate list (not "int") to list Polymorphism is based on delegation part4/02.py
  121. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-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 action part4/03.py
  122. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-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 action part4/03.py
  123. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-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 action part4/03.py
  124. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-29 34 door = Door() bool_door = BooleanDoor() Polymorphism in action
  125. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-30 34 door = Door() bool_door = BooleanDoor() room = Room(door) bool_room = Room(bool_door) Polymorphism in action
  126. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-31 34 door = Door() bool_door = BooleanDoor() room = Room(door) bool_room = Room(bool_door) room.open() room.is_open() True room.close() room.is_open() False Polymorphism in action
  127. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-32 34 door = Door() bool_door = BooleanDoor() room = Room(door) bool_room = Room(bool_door) room.open() room.is_open() True room.close() room.is_open() False bool_room.open() bool_room.is_open() True bool_room.close() bool_room.is_open() False Polymorphism in action
  128. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-33 34 “Ask for permission” style if hasattr(someobj, 'open'): [...] else: [...] It It has has the attribute the attribute
  129. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    IV-34 34 “Ask for permission” style try: someobj.open() [...] except AttributeError: [...] It It behaves behaves like it has like it has the attribute the attribute
  130. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    V-2 20 Everything is an object (again) a = 5 type(a) <class 'int'> a.__class__ <class 'int'> a.__class__.__bases__ (<class 'object'>,) object.__bases__ ()
  131. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    V-3 20 Everything is an object (again) a = 5 type(a) <class 'int'> a.__class__ <class 'int'> a.__class__.__bases__ (<class 'object'>,) object.__bases__ () 'int' 'int' inherits from inherits from (its base is) 'object' (its base is) 'object' 'a' 'a' is an is an instance of instance of (its type is) 'int' (its type is) 'int' object int a
  132. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    V-4 20 Everything is an object (again) a = 5 type(a) <class 'int'> a.__class__ <class 'int'> a.__class__.__bases__ (<class 'object'>,) object.__bases__ () Inheritance Inheritance: 'int' finds : 'int' finds here attributes and here attributes and methods methods Instance Instance: 'a' : 'a' description as a description as a class is here class is here object int a
  133. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    V-5 20 Everything is an object (again) type(a) <class 'int'> type(int) <class 'type'> object int a
  134. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    V-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
  135. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    V-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
  136. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    V-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 from from (its base is) (its base is) 'object' 'object' 'int' 'int' is an instance of is an instance of (its type is) 'type' (its type is) 'type'
  137. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    V-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 methods methods 'int' description as a 'int' description as a class is here class is here
  138. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    V-10 20 Food for thought type(object) <class 'type'> type.__bases__ (<class 'object'>,)
  139. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    V-11 20 Food for thought type(object) <class 'type'> type.__bases__ (<class 'object'>,) object type
  140. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    V-12 20 type(object) <class 'type'> type.__bases__ (<class 'object'>,) type(type) <class 'type'> object type Fatality
  141. Python 2.x Object-oriented Python from scratch – lgiordani.com - CC

    BY-SA 4.0 V-13 20 type(object) <class 'type'> type.__bases__ (<class 'object'>,) type(type) <type 'type'> object type Fatality
  142. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    V-14 20 Metaclasses class MyType(type): pass class MySpecialClass(metaclass=MyType): pass part5/01.py
  143. Python 2.x Object-oriented Python from scratch – lgiordani.com - CC

    BY-SA 4.0 V-15 20 Metaclasses class MyType(type): pass class MySpecialClass(object): __metaclass__ = MyType
  144. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    V-16 20 Metaclasses class MyType(type): pass class MySpecialClass(metaclass=MyType): pass msp = MySpecialClass() type(msp) <class '__main__.MySpecialClass'>
  145. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    V-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'>,)
  146. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    V-18 20 Metaclasses in action: singleton part5/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
  147. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    V-19 20 Metaclasses in action: singleton part5/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()
  148. Object-oriented Python from scratch – lgiordani.com - CC BY-SA 4.0

    V-20 20 Metaclasses in action: singleton part5/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 b True hex(id(a)) '0xb68030ec' hex(id(b)) '0xb68030ec'
  149. A lot of people provided free information and code Font

    aswesome icons by Freepik Python 3 OOP series http://lgiordani.com/blog/categories/python3/ Some links about Python OOP http://goo.gl/UBdJDT CAST