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

Dive Into Object-oriented Python

Dive Into Object-oriented Python

Slides of a tutorial on Python Object-oriented programming.

Leonardo Giordani

April 17, 2016
Tweet

More Decks by Leonardo Giordani

Other Decks in Programming

Transcript

  1. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani About

    Me Born in 1977 with Star Wars, bash, Apple ][, BSD, finger, Zork, Galaxy Express 999, Little Pollon, Dire Straits, The Police, Rumours, The Silmarillion, Squad Leader. Interested in operating systems and computer languages, photography, fantasy and science fiction, video- and boardgames, guitar playing, climbing, horseback riding, Aikido, rollerskating, drawing, painting, bookbinding. I programmed in Z80 and x86 Assembly, GW-Basic, Logo, Borland Turbo Pascal, Prolog, C, C++, PHP, Lisp, Ada, Objective-C, bash, Python, Erlang, Clojure, Scala, JavaScript. I love mathematics and cryptography. tl; dr me = nerd + coder
  2. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani The

    Digital Cat thedigitalcatonline.com @thedigicat @tw_lgiordani lgiordani LeonardoGiordani Get in touch
  3. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani import

    users import talk assert all([a >= users.beginner for a in talk.attendees]) About You
  4. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Objects

    Class and instance Delegation Polymorphism Overview
  5. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Source

    Code Repository http://github.com/lgiordani/oopy
  6. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani data

    = (13, 63, 5, 378, 58, 40) def avg(d): return sum(d)/len(d) >>> avg(data) 92.83333333333333 Plain old procedures
  7. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani door1

    = [1, 'closed'] door2 = [2, 'closed'] def open_door(door): door[1] = 'open' >>> open_door(door1) >>> door1 [1, 'open'] Procedures can modify data
  8. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani door1

    = [1, 'closed'] door2 = [2, 'closed'] ldoor1 = [1, 'closed', 'unlocked'] def open_door(door): door[1] = 'open' def open_ldoor(door): if door[2] == 'unlocked': door[1] = 'open' Things can get complicated
  9. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani door1

    = [1, 'closed'] door2 = [2, 'closed'] ldoor1 = [1, 'closed', 'unlocked'] def open_door(door): door[1] = 'open' def open_ldoor(door): if door[2] == 'unlocked': door[1] = 'open' >>> open_door(door1) >>> door1 [1, 'open'] >>> open_ldoor(ldoor1) >>> ldoor1 [1, 'open', 'unlocked'] Things can get complicated
  10. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani The

    meaning of the word 'type' Behavioural meaning
  11. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani The

    meaning of the word 'type' Structural meaning
  12. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani ©

    2000 Alex Martelli on comp.lang.python Duck typing: make it behave like a duck
  13. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    a = 6 >>> a 6 >>> type(a) <class 'int'> >>> a = int(6) >>> a 6 >>> a.__class__ <class 'int'> You already used classes
  14. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani You

    already used classes >>> a = 6 >>> a 6 >>> type(a) <type 'int'> >>> a = int(6) >>> a 6 >>> a.__class__ <type 'int'> 2.x
  15. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Exercises

    1. Find some types that Python provides out of the box. 2. Can you create a float variable without using the '.' character? (i.e. do not write a=5.4). 3. What is the difference between {1,2,3} and {'a':1, 'b':2}? How can you tell it?
  16. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Exercises

    1. Find some types that Python provides out of the box. >>> type(4) <class 'int'> >>> type(4.5) <class 'float'> >>> type('some words') <class 'str'> >>> type([1,2,3,4]) <class 'list'> >>> type((1,2,3,4)) <class 'tuple'> >>> type({1,2,3,4}) <class 'set'> >>> type({'first name':'Ray', 'last name':'Stantz'}) <class 'dict'> >>> type(True) <class 'bool'>
  17. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Exercises

    2. Can you create a float variable without using the '.' character? (i.e. do not write a=5.4). >>> a = float(4) >>> type(a) <class 'float'>
  18. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Exercises

    3. What is the difference between {1,2,3} and {'a':1, 'b':2}? How can you tell it? >>> type({1,2,3}) <class 'set'> >>> type({'a':1, 'b':2}) <class 'dict'>
  19. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 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 first class
  20. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 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' The first class 2.x
  21. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 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 first class
  22. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    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'
  23. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    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'
  24. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    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'
  25. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    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'
  26. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    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'
  27. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Exercises

    1. Create a ColouredDoor class that has the colour attribute. 2. Create a ClosedDoor class that has a default status of 'closed'. 3. Create a ToggleDoor class that has a method toggle() that toggles the status of the door.
  28. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 1.

    Create a ColouredDoor class that has the colour attribute. class ColouredDoor: def __init__(self, number, status, colour): self.number = number self.status = status self.colour = colour def open(self): self.status = 'open' def close(self): self.status = 'closed' Exercises
  29. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 2.

    Create a ClosedDoor class that has a default status of 'closed'. class ClosedDoor: def __init__(self, number, status='closed'): self.number = number self.status = status def open(self): self.status = 'open' def close(self): self.status = 'closed' Exercises
  30. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 3.

    Create a ToggleDoor class that has a method toggle() that toggles the status of the door. class ToggleDoor: def __init__(self, number, status): self.number = number self.status = status def open(self): self.status = 'open' def close(self): self.status = 'closed' def toggle(self): d = {'open': 'closed', 'closed': 'open'} self.status = d[self.status] Exercises
  31. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Where

    is the class of an object? >>> door1 = Door(1, 'closed') >>> door2 = Door(1, 'closed')
  32. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Where

    is the class of an object? >>> door1 = Door(1, 'closed') >>> door2 = Door(1, 'closed') >>> hex(id(door1)) '0xb67e148c' >>> hex(id(door2)) '0xb67e144c'
  33. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 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'
  34. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Class

    attributes class Door: colour = 'brown' def __init__(self, number, status): self.number = number self.status = status def open(self): self.status = 'open' def close(self): self.status = 'closed'
  35. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Class

    attributes >>> door1 = Door(1, 'closed') >>> door2 = Door(2, 'closed')
  36. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Class

    attributes >>> door1 = Door(1, 'closed') >>> door2 = Door(2, 'closed') >>> Door.colour 'brown' >>> door1.colour 'brown' >>> door2.colour 'brown'
  37. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Class

    attributes >>> Door.colour = 'white' >>> Door.colour 'white' >>> door1.colour 'white' >>> door2.colour 'white'
  38. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Class

    attributes >>> 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'
  39. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Class

    attributes >>> 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>})
  40. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Class

    attributes >>> 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'}
  41. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Class

    attributes >>> 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'
  42. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Class

    attributes >>> 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
  43. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Attribute

    resolution Door door1 __getattribute__() door1.colour Door.colour door2
  44. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    door1 = Door(1, 'closed') >>> door1.colour = 'white' >>> door1.__dict__['colour'] 'white' >>> door1.__class__.__dict__['colour'] 'brown' Attribute resolution
  45. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    door1 = Door(1, 'closed') >>> door1.colour = 'white' >>> door1.__dict__['colour'] 'white' >>> door1.__class__.__dict__['colour'] 'brown' >>> door1.colour 'white' >>> Door.colour 'brown' Attribute resolution
  46. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    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' Attribute resolution
  47. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    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' Attribute resolution
  48. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Exercises

    1. Modify the Door class adding a class attribute 'status' with value 'undefined'. Does it work? What happens to instances? 2. Modify the Door class adding a class attribute 'status' with value 'closed' and remove status from __init__(). Does it work? 3. Add a toggle() method to the previous class. What happens if you call toggle() on a fresh instance? Why?
  49. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 1.

    Modify the Door class adding a class attribute 'status' with value 'undefined'. Does it work? What happens to instances? class Door: colour = 'brown' status = 'undefined' def __init__(self, number, status): self.number = number self.status = status def open(self): self.status = 'open' def close(self): self.status = 'closed' Exercises
  50. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 2.

    Modify the Door class adding a class attribute 'status' with value 'closed' and remove status from __init__(). Does it work? class Door: colour = 'brown' status = 'closed' def __init__(self, number): self.number = number def open(self): self.status = 'open' def close(self): self.status = 'closed' Exercises
  51. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 3.

    Add a toggle() method to the previous class. What happens if you call toggle() on a fresh instance? Why? class Door: colour = 'brown' status = 'closed' def __init__(self, number): self.number = number def toggle(self): d = {'open': 'closed', 'closed': 'open'} self.status = d[self.status] Exercises
  52. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    Door.__dict__ mappingproxy({'open': <function Door.open at 0xb68604ac>, 'colour': 'white', ...}) >>> door1.__dict__ {'number': 1, 'status': 'closed'} >>> door1.colour is Door.colour True Method resolution
  53. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    Door.__dict__ mappingproxy({'open': <function Door.open at 0xb68604ac>, 'colour': 'white', ...}) >>> door1.__dict__ {'number': 1, 'status': 'closed'} >>> door1.colour is Door.colour True >>> door1.open is Door.open False Method resolution
  54. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    Door.__dict__ mappingproxy({'open': <function Door.open at 0xb68604ac>, 'colour': 'white', ...}) >>> 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>> Method resolution
  55. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    Door.__dict__ mappingproxy({'open': <function Door.open at 0xb68604ac>, 'colour': 'white', ...}) >>> 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>> Method resolution 2.x
  56. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Class

    methods 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'
  57. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    door1 = Door(1, 'closed') >>> door1.knock() Knock! Class methods
  58. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    door1 = Door(1, 'closed') >>> door1.knock() Knock! >>> Door.knock() Knock! Class methods
  59. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Class

    methods 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 ...
  60. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    door1 = Door(1, 'closed') >>> door2 = Door(2, 'closed') Class methods
  61. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    door1 = Door(1, 'closed') >>> door2 = Door(2, 'closed') >>> Door.colour 'brown' >>> door1.colour 'brown' >>> door2.colour 'brown' Class methods
  62. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    Door.paint('white') >>> Door.colour 'white' >>> door1.colour 'white' >>> door2.colour 'white' Class methods
  63. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    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
  64. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Exercises

    1. Modify the Door class adding a class method 'paint' that accepts a 'colour' arg and changes the class attribute 'colour'. 2. Modify the Door class adding both a class method 'paint' and a standard method 'paint'. What happens?
  65. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 1.

    Modify the Door class adding a class method 'paint' that accepts a 'colour' arg and changes the class attribute 'colour'. class Door: colour = 'brown' def __init__(self, number, status): self.number = number self.status = status @classmethod def paint(cls, colour): cls.colour = colour def paint(self, colour): self.colour = colour [...] Exercises
  66. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 2.

    Modify the Door class adding both a class method 'paint' and a standard method 'paint'. What happens? Exercises class Door: colour = 'brown' def __init__(self, number, status): self.number = number self.status = status @classmethod def open(cls, colour): cls.colour = colour def open(self): self.status = 'open' def close(self): self.status = 'closed'
  67. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Specialization

    Cat Animal Cat has all the features of Animal, i.e. 'moves'
  68. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Specialization

    Cat Animal Cat can provide new features, i.e. 'has whiskers'
  69. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Specialization

    Cat Animal Cat performs some or all the tasks performed by Animal in a different way, i.e. 'moves silently'
  70. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Delegation

    Cat Animal Cat implements only 'new' or 'changed' features and delegates the remaining features to Animal
  71. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Composition:

    'to have' Car Engine Wheels turn_on() get_color() steer() turn_on() steer()
  72. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Inheritance

    class SecurityDoor(Door): pass >>> sdoor = SecurityDoor(1, 'closed')
  73. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Inheritance

    class SecurityDoor(Door): pass >>> sdoor = SecurityDoor(1, 'closed') >>> SecurityDoor.colour is Door.colour True >>> sdoor.colour is Door.colour True
  74. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Inheritance

    class SecurityDoor(Door): pass >>> sdoor = SecurityDoor(1, 'closed') >>> SecurityDoor.colour is Door.colour True >>> sdoor.colour is Door.colour True sdoor.colour SecurityDoor.colour Door.colour
  75. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Inheritance

    >>> sdoor.__dict__ {'number': 1, 'status': 'closed'}
  76. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Inheritance

    >>> sdoor.__dict__ {'number': 1, 'status': 'closed'} >>> sdoor.__class__.__dict__ mappingproxy({'__doc__': None, '__module__': '__main__'})
  77. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 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. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    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'>,) Inheritance
  79. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    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'>> Inheritance
  80. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Overriding

    class SecurityDoor(Door): colour = 'grey' locked = True def open(self): if not self.locked: self.status = 'open'
  81. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Overriding

    class SecurityDoor(Door): colour = 'grey' locked = True def open(self): if not self.locked: self.status = 'open' >>> SecurityDoor.__dict__ mappingproxy({'__doc__': None, '__module__': '__main__', 'open': <function SecurityDoor.open at 0xb6fcf89c>, 'colour': 'grey', 'locked': True})
  82. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Exercises

    1. Modify the SecurityDoor class adding a custom close_and_lock() method that changes status to 'closed' and locked to True. Test it. 2. Modify the SecurityDoor class adding a custom close() method that accepts a locked flag (with default). 3. Modify the SecurityDoor class adding a custom __init__() method that sets self.locked.
  83. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 1.

    Modify the SecurityDoor class adding a custom close_and_lock() method that changes status to 'closed' and locked to True. Test it. class SecurityDoor(Door): colour = 'grey' locked = False def open(self): if not self.locked: self.status = 'open' def close_and_lock(self): self.status = 'closed' self.locked = True Exercises
  84. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 2.

    Modify the SecurityDoor class adding a custom close() method that accepts a locked flag (with default). class SecurityDoor(Door): colour = 'grey' locked = False def open(self): if not self.locked: self.status = 'open' def close(self, locked=False): self.status = 'closed' self.locked = locked Exercises
  85. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 3.

    Modify the SecurityDoor class adding a custom __init__() method that sets self.locked. class SecurityDoor(Door): colour = 'grey' def __init__(self, number, status, locked=False): self.number = number self.status = status self.locked = locked def open(self): if not self.locked: self.status = 'open' Exercises
  86. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Overriding

    class SecurityDoor(Door): colour = 'grey' locked = True def open(self): if self.locked: return Door.open(self)
  87. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Overriding

    class SecurityDoor(Door): colour = 'grey' locked = True def open(self): if self.locked: return Door.open(self) >>> sdoor = SecurityDoor(1, 'closed') >>> sdoor.status 'closed'
  88. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Overriding

    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'
  89. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Overriding

    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'
  90. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Avoid

    strong coupling class SecurityDoor(Door): colour = 'grey' locked = True def open(self): if self.locked: return super().open()
  91. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Avoid

    strong coupling class SecurityDoor(Door): colour = 'grey' locked = True def open(self): if self.locked: return super(SecurityDoor, self).open() 2.x
  92. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Composition

    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()
  93. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Composition

    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: 'SecurityDoor' object has no attribute 'status'
  94. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Composition

    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'
  95. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 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'
  96. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Composed

    inheritance? class ComposedDoor: def __init__(self, number, status): self.door = Door(number, status) def __getattr__(self, attr): return getattr(self.door, attr)
  97. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Exercises

    1. Modify the SecurityDoor class adding a custom close_and_lock() method. Use super(). Try to implement it with composition. 2. Modify the SecurityDoor class adding a custom close() method that accepts a locked flag (with default). Use super(). Try to implement it with composition.
  98. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 1.

    Modify the SecurityDoor class adding a custom close_and_lock() method. Use super(). Try to implement it with composition. class SecurityDoor(Door): #inheritance colour = 'grey' def __init__(self, number, status, locked=False): super().__init__(number, status) self.locked = locked def open(self): if self.locked: return super().open() def close_and_lock(self): super().close() self.locked = True Exercises
  99. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani class

    SecurityDoor: #composition colour = 'grey' def __init__(self, number, status, locked=False): self.door = Door(number, status) self.locked = locked def open(self): if self.locked: return self.door.open() def __getattr__(self, attr): return getattr(self.door, attr) def close_and_lock(self): self.door.close() self.locked = True Exercises
  100. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 2.

    Modify the SecurityDoor class adding a custom close() method that accepts a locked flag (with default). Use super(). Try to implement it with composition. class SecurityDoor(Door): #inheritance colour = 'grey' def __init__(self, number, status, locked=False): super().__init__(number, status) self.locked = locked def open(self): if self.locked: return super().open() def close(self, locked=False): super().close() self.locked = locked Exercises
  101. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani class

    SecurityDoor: #composition colour = 'grey' def __init__(self, number, status, locked=False): self.door = Door(number, status) self.locked = locked def open(self): if self.locked: return self.door.open() def __getattr__(self, attr): return getattr(self.door, attr) def close(self, locked=False): self.door.close() self.locked = locked Exercises
  102. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 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']
  103. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani getattr()

    >>> l = [1,2,3] >>> dir(l) [..., '__subclasshook__', 'append', 'clear', ...]
  104. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani getattr()

    >>> l = [1,2,3] >>> dir(l) [..., '__subclasshook__', 'append', 'clear', ...] >>> l.append <built-in method append of list object at 0xb70a2c2c>
  105. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani getattr()

    >>> l = [1,2,3] >>> dir(l) [..., '__subclasshook__', 'append', 'clear', ...] >>> l.append <built-in method append of list object at 0xb70a2c2c> >>> a = l.append >>> a <built-in method append of list object at 0xb70a2c2c>
  106. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani getattr()

    >>> l = [1,2,3] >>> dir(l) [..., '__subclasshook__', 'append', 'clear', ...] >>> 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>
  107. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani getattr()

    >>> l = [1,2,3] >>> dir(l) [..., '__subclasshook__', 'append', 'clear', ...] >>> 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
  108. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    a = 5 >>> a 5 >>> type(a) <class 'int'> >>> hex(id(a)) '0x83fe540' References
  109. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    a = 5 >>> a 5 >>> type(a) <class 'int'> >>> hex(id(a)) '0x83fe540' >>> a = 'five' >>> a 'five' References
  110. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    a = 5 >>> a 5 >>> type(a) <class 'int'> >>> hex(id(a)) '0x83fe540' >>> a = 'five' >>> a 'five' >>> type(a) <class 'str'> >>> hex(id(a)) '0xb70d6560' References
  111. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    a = 5 >>> a 5 >>> type(a) <class 'int'> >>> hex(id(a)) '0x83fe540' >>> a = 'five' >>> a 'five' >>> type(a) <class 'str'> >>> hex(id(a)) '0xb70d6560' References Strong type system: every variable has a type
  112. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    a = 5 >>> a 5 >>> type(a) <class 'int'> >>> hex(id(a)) '0x83fe540' >>> a = 'five' >>> a 'five' >>> type(a) <class 'str'> >>> hex(id(a)) '0xb70d6560' References Dynamic type system: the type changes with the content
  113. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani def

    echo(a): return a >>> echo(5) 5 >>> echo('five') 'five' Variables are references
  114. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani What

    is polymorphism? >>> 5 + 6 11 >>> 5.5 + 6.6 12.1
  115. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani What

    is polymorphism? >>> 5 + 6 11 >>> 5.5 + 6.6 12.1 >>> "just a" + " string" 'just a string'
  116. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani What

    is polymorphism? >>> 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)
  117. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani What

    is polymorphism? >>> 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'
  118. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani What

    is polymorphism? >>> s = "Just a sentence" >>> len(s) 15 >>> l = [1, 2, 3] >>> len(l) 3 >>> d = {'a': 1, 'b': 2} >>> len(d) 2
  119. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani What

    is polymorphism? >>> 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()
  120. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani What

    is polymorphism? >>> s.__len__() 15 >>> l.__len__() 3 >>> d.__len__() 2
  121. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani What

    is polymorphism? >>> 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__'
  122. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Polymorphism

    is based on delegation >>> [1,2,3].__add__([4,5,6]) [1, 2, 3, 4, 5, 6]
  123. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Polymorphism

    is based on delegation >>> [1,2,3].__add__([4,5,6]) [1, 2, 3, 4, 5, 6] >>> dir([1,2,3]) ['__add__', '__class__', '__contains__', ...]
  124. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Polymorphism

    is based on delegation >>> [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
  125. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Polymorphism

    is based on delegation >>> [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
  126. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Polymorphism

    is based on delegation 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]
  127. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Polymorphism

    is based on delegation 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
  128. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Exercises

    1. Create a class that contains an integer as self.value and with a __len__() method that returns the number of digits of the integer. Does len() work for instances of this class? 2. Add a __contains__() method that returns True if self.value contains the given digit. Does 'in' work for this type? 3. Try str() on an instance of your class. What happens? How can you return a better string representation (e.g. to show the actual value)?
  129. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 1.

    Create a class that contains an integer as self.value and with a __len__() method that returns the number of digits of the integer. Does len() work for instances of this class? class CustomInteger: def __init__(self, value): self.value = value def __len__(self): return len(str(self.value)) Exercises
  130. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 2.

    Add a __contains__() method that returns True if self.value contains the given digit. Does 'in' work for this type? class CustomInteger: def __init__(self, value): self.value = value def __len__(self): return len(str(self.value)) def __contains__(self, digit): return str(digit) in str(self.value) Exercises
  131. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 3.

    Try str() on an instance of your class. What happens? How can you return a better string representation (e.g. to show the actual value)? class CustomInteger: def __init__(self, value): self.value = value def __len__(self): return len(str(self.value)) def __contains__(self, digit): return str(digit) in str(self.value) def __str__(self): return super().__str__() + ' [{}]'.format(self.value) Exercises
  132. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Polymorphism

    in action 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()
  133. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Polymorphism

    in action 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"
  134. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Polymorphism

    in action 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
  135. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    door = Door() >>> bool_door = BooleanDoor() Polymorphism in action
  136. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    door = Door() >>> bool_door = BooleanDoor() >>> room = Room(door) >>> bool_room = Room(bool_door) Polymorphism in action
  137. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    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
  138. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani >>>

    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
  139. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Exercises

    1. Modify the Room, the Door and the BooleanDoor classes to add a toggle() method that changes open status to closed and vice versa. 2. Change the Room class such that it accepts a class instead of an instance. How do you manage it into __init__()? Does it still work? 3. Create a PetDoor object that inherits from Door (or BooleanDoor). Add the suitable methods to manage the small pet door. Does the Room work? 4. May you reuse the Door to create the pet door?
  140. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 1.

    Modify the Room, the Door and the BooleanDoor classes to add a toggle() method that changes open status to closed and vice versa. class Room: def __init__(self, door): self.door = door def open(self): self.door.open() def close(self): self.door.close() def is_open(self): return self.door.is_open() def toggle(self): if self.door.is_open(): self.door.close() else: self.door.open() Exercises
  141. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 2.

    Change the Room class such that it accepts a class instead of an instance. How do you manage it into __init__()? Does it still work? class Room: def __init__(self, door_cls): self.door = door_cls() def open(self): self.door.open() def close(self): self.door.close() def is_open(self): return self.door.is_open() >>> room = Room(Door) >>> bool_room = Room(BooleanDoor) Exercises
  142. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 3.

    Create a PetDoor object that inherits from Door (or BooleanDoor). Add the suitable methods to manage the small pet door. Does the Room work? class PetDoor(BooleanDoor): def __init__(self): super().__init__() self.pet_door = 'open' def open_pet_door(self): self.pet_door = 'open' def close_pet_door(self): self.pet_door = 'closed' Exercises
  143. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani 4.

    May you reuse the Door to create the pet door? class PetDoor(BooleanDoor): def __init__(self): super().__init__() self.pet_door = BooleanDoor() def open_pet_door(self): self.pet_door.open() def close_pet_door(self): self.pet_door.close() Exercises
  144. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani if

    hasattr(someobj, 'open'): [...] else: [...] “Ask for permission” style
  145. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani try:

    someobj.open() [...] except AttributeError: [...] “Ask for forgiveness” style
  146. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Cast

    Font awesome icons by Freepik Guido van Rossum and the Python core developers Open source programmers, stackoverflow and forum contributors, blog authors, convention and meetup attendees Many hours spent studying and experimenting
  147. Dive into Object-Oriented Python – Leonardo Giordani - @lgiordani Cast

    thedigitalcatonline.com Interested in AMQP, C, Clojure, concurrent programming, C++, decorators, Django, Erlang, functional programming, generators, Git, metaclasses, metaprogramming, Notebook, OOP, operating systems, Python, Qt, RabbitMQ, Scala, TDD, versioning? @thedigicat