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

Deep Inside Object-Oriented Python - PyCon Ireland 2014

Deep Inside Object-Oriented Python - PyCon Ireland 2014

Slides of the "Deep Inside Object-oriented Python" presentation held in Dublin at PyConIE 2014.

See the full series of articles on my blog http://lgiordani.com

Leonardo Giordani

October 11, 2014
Tweet

More Decks by Leonardo Giordani

Other Decks in Programming

Transcript

  1. DEEP INSIDE
    OBJECT-ORIENTED
    PYTHON
    Leonardo Giordani
    lgiordani.com
    PyCon Ireland 2014

    View Slide

  2. ABOUT ME
    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.
    https://github.com/
    lgiordani
    https://twitter.com/
    tw_lgiordani
    https://plus.google.com/u/
    LeonardoGiordani
    The Digital Cat
    http://lgiordani.com

    View Slide

  3. ABOUT YOU
    To enjoy this tutorial and avoid falling
    asleep you should fit at least one of
    the following descriptions:
    * A Python beginner without any
    knowledge of OOP languages.
    * A Python beginner with knowledge
    of other OOP languages such as C++,
    Java, Ruby, etc.
    * A Python advanced user who has
    some knowledge about Python OOP
    but now wants to know what happens
    “behind the scenes”.
    Python experts: you shouldn't be here.
    You are going to be bored.
    No, seriously.

    View Slide

  4. ABOUT
    THIS
    TUTORIAL
    A beginners' introduction to the Python implementation of
    OOP concepts. Covers the following topics
    * Objects and types
    * Classes and members
    * Delegation
    * Polymorphism
    * Metaclasses
    This tutorial covers Python 3. Almost all concepts are valid for
    Python 2, when relevant differences will be highlighted.
    Source posts: http://lgiordani.com/blog/categories/python3/

    View Slide

  5. SOURCE
    CODE
    https://github.com/lgiordani/
    deep_inside_oop_python
    Code snippets used in this tutorial can be found at

    View Slide

  6. PART 1
    Objects and types

    View Slide

  7. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    7 163
    1
    2
    3
    4
    5
    6
    # This is some data
    data = (13, 63, 5, 378, 58, 40)
    # This is a procedure that computes the average
    def avg(d):
    return sum(d)/len(d)
    Plain old procedures
    >>> avg(data)
    92.83333333333333
    >>>
    part1/01.py

    View Slide

  8. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    8 163
    1
    2
    3
    4
    5
    6
    # This is some data
    data = (13, 63, 5, 378, 58, 40)
    # This is a procedure that computes the average
    def avg(d):
    return sum(d)/len(d)
    Very simple data: a sequence of numbers
    Original data enters here
    This returns new data
    Plain old procedures
    part1/01.py

    View Slide

  9. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    9 163
    1
    2
    3
    4
    5
    6
    7
    # These are two numbered doors, initially closed
    door1 = [1, 'closed']
    door2 = [2, 'closed']
    # This procedure opens a door
    def open_door(door):
    door[1] = 'open'
    Procedures can modify data
    >>> open_door(door1)
    >>> door1
    [1, 'open']
    >>>
    part1/02.py

    View Slide

  10. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    10 163
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # These are two standard doors, initially closed
    door1 = [1, 'closed']
    door2 = [2, 'closed']
    # This is a lockable door, initially closed and unlocked
    ldoor1 = [1, 'closed', 'unlocked']
    # This procedure opens a standard door
    def open_door(door):
    door[1] = 'open'
    # This procedure opens a lockable door
    def open_ldoor(door):
    if door[2] == 'unlocked':
    door[1] = 'open'
    Things can get complicated
    >>> open_door(door1)
    >>> door1
    [1, 'open']
    >>> open_ldoor(ldoor1)
    >>> ldoor1
    [1, 'open', 'unlocked']
    part1/03.py

    View Slide

  11. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    11 163
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # These are two standard doors, initially closed
    door1 = [1, 'closed']
    door2 = [2, 'closed']
    # This is a lockable door, initially closed and unlocked
    ldoor1 = [1, 'closed', 'unlocked']
    # This procedure opens a standard door
    def open_door(door):
    door[1] = 'open'
    # This procedure opens a lockable door
    def open_ldoor(door):
    if door[2] == 'unlocked':
    door[1] = 'open'
    Things can get complicated
    >>> open_door(door1)
    >>> door1
    [1, 'open']
    >>> open_ldoor(ldoor1)
    >>> ldoor1
    [1, 'open', 'unlocked']
    Same “action”
    You must use the right function
    part1/03.py

    View Slide

  12. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    12 163
    The meaning of the word 'type'
    Behaves like a duck
    Behavioural meaning

    View Slide

  13. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    13 163
    The meaning of the word 'type'
    Dissection reveals
    the truth
    Structural meaning

    View Slide

  14. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    14 163
    The behavioural meaning is important
    Duck typing: making it behave like a duck
    'Type' is a noun,
    please.

    View Slide

  15. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    15 163
    Class: the generic concept
    Instance: a specific object of that type

    View Slide

  16. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    16 163
    Classes
    >>> a = 6
    >>> a
    6
    >>> type(a)

    >>> a.__class__

    >>>

    View Slide

  17. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    17 163
    Python
    2.x
    Python
    2.x
    Classes
    >>> a = 6
    >>> a
    6
    >>> type(a)

    >>> a.__class__

    >>>

    View Slide

  18. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    18 163
    Classes
    >>> a = 6
    >>> a
    6
    >>> type(a)

    >>> a.__class__

    >>>
    What is the type of 'a'?
    The type of 'a' is the 'int' class
    It is written INSIDE the variable!

    View Slide

  19. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    19 163
    The first class
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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'
    part1/04.py

    View Slide

  20. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    20 163
    Python
    2.x
    Python
    2.x
    The first class
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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'
    part1/04.py

    View Slide

  21. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    21 163
    The first class
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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
    Everything under the 'class' keyword is part of the class
    part1/04.py

    View Slide

  22. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    22 163
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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
    Functions inside a class are called
    'methods', and must accept 'self'
    as the first parameter
    part1/04.py

    View Slide

  23. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    23 163
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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
    Attributes
    Both attributes and methods are 'members' of the class
    part1/04.py

    View Slide

  24. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    24 163
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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
    The __init__() special method, part of
    the constructor mechanism
    part1/04.py

    View Slide

  25. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    25 163
    The first class
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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'
    >>> door1 = Door(1, 'closed')
    >>>
    part1/04.py

    View Slide

  26. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    26 163
    The first class
    >>> door1 = Door(1, 'closed')
    >>> type(door1)

    >>>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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'
    part1/04.py

    View Slide

  27. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    27 163
    The first class
    >>> door1 = Door(1, 'closed')
    >>> type(door1)

    >>> door1.number
    1
    >>> door1.status
    'closed'
    >>>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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'
    part1/04.py

    View Slide

  28. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    28 163
    The first class
    >>> door1 = Door(1, 'closed')
    >>> type(door1)

    >>> door1.number
    1
    >>> door1.status
    'closed'
    >>> door1.open()
    >>>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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'
    part1/04.py

    View Slide

  29. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    29 163
    The first class
    >>> door1 = Door(1, 'closed')
    >>> type(door1)

    >>> door1.number
    1
    >>> door1.status
    'closed'
    >>> door1.open()
    >>> door1.number
    1
    >>> door1.status
    'open'
    >>>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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'
    part1/04.py

    View Slide

  30. PART 2
    Classes and members

    View Slide

  31. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    31 163
    Everything is an object
    >>> a = 1
    >>> type(a)

    >>>

    View Slide

  32. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    32 163
    Everything is an object
    >>> a = 1
    >>> type(a)

    >>> type(int)

    The type of an object is an object itself

    View Slide

  33. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    33 163
    Where is the class of an object?
    >>> door1 = Door(1, 'closed')
    >>> door2 = Door(1, 'closed')
    >>>

    View Slide

  34. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    34 163
    Where is the class of an object?
    >>> door1 = Door(1, 'closed')
    >>> door2 = Door(1, 'closed')
    >>> hex(id(door1))
    '0xb67e148c'
    >>> hex(id(door2))
    '0xb67e144c'
    >>>

    View Slide

  35. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    35 163
    Where is the class of an object?
    >>> door1 = Door(1, 'closed')
    >>> door2 = Door(1, 'closed')
    >>> hex(id(door1))
    '0xb67e148c'
    >>> hex(id(door2))
    '0xb67e144c'
    >>> Your numbers will be different from these

    View Slide

  36. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    36 163
    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! It is an
    object in the system.

    View Slide

  37. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    37 163
    Class attributes
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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'
    part2/01.py

    View Slide

  38. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    38 163
    Class attributes
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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
    part2/01.py

    View Slide

  39. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    39 163
    Class attributes
    >>> door1 = Door(1, 'closed')
    >>> door2 = Door(2, 'closed')
    >>>
    1
    2
    class Door:
    colour = 'brown'
    [...]
    part2/01.py

    View Slide

  40. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    40 163
    Class attributes
    >>> door1 = Door(1, 'closed')
    >>> door2 = Door(2, 'closed')
    >>> Door.colour
    'brown'
    >>> door1.colour
    'brown'
    >>> door2.colour
    'brown'
    >>>
    1
    2
    class Door:
    colour = 'brown'
    [...]
    part2/01.py

    View Slide

  41. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    41 163
    Class attributes
    >>> door1 = Door(1, 'closed')
    >>> door2 = Door(2, 'closed')
    >>> Door.colour
    'brown'
    >>> door1.colour
    'brown'
    >>> door2.colour
    'brown'
    >>> Door.colour = 'white'
    >>> Door.colour
    'white'
    >>> door1.colour
    'white'
    >>> door2.colour
    'white'
    >>>
    1
    2
    class Door:
    colour = 'brown'
    [...]
    part2/01.py

    View Slide

  42. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    42 163
    Class attributes
    1
    2
    class Door:
    colour = 'brown'
    [...]
    >>> door1 = Door(1, 'closed')
    >>> door2 = Door(2, 'closed')
    >>> Door.colour
    'brown'
    >>> door1.colour
    'brown'
    >>> door2.colour
    'brown'
    >>> 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'
    >>>
    part2/01.py

    View Slide

  43. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    43 163
    Let's dive into attribute resolution
    >>> Door.__dict__
    mappingproxy({'open': ,
    'colour': 'white',
    '__dict__': ,
    '__weakref__': ,
    '__init__': ,
    '__module__': '__main__',
    '__doc__': None,
    'close': })
    >>>
    1
    2
    class Door:
    colour = 'brown'
    [...]
    part2/01.py

    View Slide

  44. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    44 163
    Let's dive into attribute resolution
    >>> Door.__dict__
    mappingproxy({'open': ,
    'colour': 'white',
    '__dict__': ,
    '__weakref__': ,
    '__init__': ,
    '__module__': '__main__',
    '__doc__': None,
    'close': })
    >>> door1.__dict__
    {'number': 1, 'status': 'closed'}
    >>>
    1
    2
    class Door:
    colour = 'brown'
    [...]
    part2/01.py

    View Slide

  45. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    45 163
    Let's dive into attribute resolution
    >>> Door.__dict__
    mappingproxy({'open': ,
    'colour': 'white',
    '__dict__': ,
    '__weakref__': ,
    '__init__': ,
    '__module__': '__main__',
    '__doc__': None,
    'close': })
    >>> door1.__dict__
    {'number': 1, 'status': 'closed'}
    >>> door1.__dict__['colour']
    Traceback (most recent call last):
    File "", line 1, in
    KeyError: 'colour'
    >>>
    1
    2
    class Door:
    colour = 'brown'
    [...]
    part2/01.py

    View Slide

  46. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    46 163
    Let's dive into attribute resolution
    >>> Door.__dict__
    mappingproxy({'open': ,
    'colour': 'white',
    '__dict__': ,
    '__weakref__': ,
    '__init__': ,
    '__module__': '__main__',
    '__doc__': None,
    'close': })
    >>> door1.__dict__
    {'number': 1, 'status': 'closed'}
    >>> door1.__dict__['colour']
    Traceback (most recent call last):
    File "", line 1, in
    KeyError: 'colour'
    >>> door1.__class__.__dict__['colour']
    'white'
    >>> door1.colour is Door.colour
    True
    1
    2
    class Door:
    colour = 'brown'
    [...]
    part2/01.py

    View Slide

  47. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    47 163
    Door
    door1 door2
    __getattribute__()
    >>> door1.colour
    >>> Door.colour
    Let's dive into attribute resolution

    View Slide

  48. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    48 163
    Let's dive into attribute resolution
    >>> door1 = Door(1, 'closed')
    >>> door1.colour = 'white'
    >>>
    1
    2
    class Door:
    colour = 'brown'
    [...]
    part2/01.py
    Remember to execute the
    class again (we manually
    changed the class 'colour'
    attribute)

    View Slide

  49. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    49 163
    Let's dive into attribute resolution
    >>> door1 = Door(1, 'closed')
    >>> door1.colour = 'white'
    >>> door1.__dict__['colour']
    'white'
    >>> door1.__class__.__dict__['colour']
    'brown'
    >>>
    1
    2
    class Door:
    colour = 'brown'
    [...]
    part2/01.py

    View Slide

  50. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    50 163
    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'
    >>>
    1
    2
    class Door:
    colour = 'brown'
    [...]
    part2/01.py

    View Slide

  51. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    51 163
    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'
    >>>
    1
    2
    class Door:
    colour = 'brown'
    [...]
    part2/01.py

    View Slide

  52. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    52 163
    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'
    >>>
    1
    2
    class Door:
    colour = 'brown'
    [...]
    part2/01.py

    View Slide

  53. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    53 163
    What about methods?
    >>> door1 = Door(1, 'closed')
    >>> Door.__dict__
    mappingproxy({'open': ,
    'colour': 'red',
    '__dict__': ,
    '__weakref__': ,
    '__init__': ,
    '__module__': '__main__',
    '__doc__': None,
    'close': })
    >>> door1.__dict__
    {'number': 1, 'status': 'closed'}
    >>> door1.colour is Door.colour
    True
    >>>

    View Slide

  54. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    54 163
    What about methods?
    >>> door1 = Door(1, 'closed')
    >>> Door.__dict__
    mappingproxy({'open': ,
    'colour': 'brown',
    '__dict__': ,
    '__weakref__': ,
    '__init__': ,
    '__module__': '__main__',
    '__doc__': None,
    'close': })
    >>> door1.__dict__
    {'number': 1, 'status': 'closed'}
    >>> door1.colour is Door.colour
    True
    >>> door1.open is Door.open
    False
    >>>

    View Slide

  55. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    55 163
    What about methods?
    >>> door1 = Door(1, 'closed')
    >>> Door.__dict__
    mappingproxy({'open': ,
    'colour': 'brown',
    '__dict__': ,
    '__weakref__': ,
    '__init__': ,
    '__module__': '__main__',
    '__doc__': None,
    'close': })
    >>> door1.__dict__
    {'number': 1, 'status': 'closed'}
    >>> door1.colour is Door.colour
    True
    >>> door1.open is Door.open
    False
    >>> Door.__dict__['open']

    >>> Door.open

    >>>

    View Slide

  56. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    56 163
    What about methods?
    >>> door1 = Door(1, 'closed')
    >>> Door.__dict__
    mappingproxy({'open': ,
    'colour': 'brown',
    '__dict__': ,
    '__weakref__': ,
    '__init__': ,
    '__module__': '__main__',
    '__doc__': None,
    'close': })
    >>> door1.__dict__
    {'number': 1, 'status': 'closed'}
    >>> door1.colour is Door.colour
    True
    >>> door1.open is Door.open
    False
    >>> Door.__dict__['open']

    >>> Door.open

    >>> door1.open
    >
    >>>

    View Slide

  57. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    57 163
    Python
    2.x
    Python
    2.x
    What about methods?
    >>> door1 = Door(1, 'closed')
    >>> Door.__dict__
    dict_proxy({'__module__': '__main__',
    'colour': 'brown',
    '__weakref__': ,
    '__dict__': ,
    'close': ,
    'open': ,
    '__doc__': None,
    '__init__': })
    >>> door1.__dict__
    {'status': 'closed', 'number': 1}
    >>> door1.colour is Door.colour
    True
    >>> door1.open is Door.open
    False
    >>> Door.__dict__['open']

    >>> Door.open

    >>> door1.open
    >
    >>>

    View Slide

  58. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    58 163
    From functions to bound methods
    >>> Door.open()
    Traceback (most recent call last):
    File "", line 1, in
    TypeError: open() missing 1 required positional argument: 'self'
    >>>

    View Slide

  59. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    59 163
    Python
    2.x
    Python
    2.x
    >>> Door.open()
    Traceback (most recent call last):
    File "", line 1, in
    TypeError: unbound method open() must be called with Door instance
    as first argument (got nothing instead)
    >>>
    From functions to bound methods

    View Slide

  60. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    60 163
    From functions to bound methods
    >>> Door.open()
    Traceback (most recent call last):
    File "", line 1, in
    TypeError: open() missing 1 required positional argument: 'self'
    >>> Door.open(door1)
    >>> door1.status
    'open'
    >>>

    View Slide

  61. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    61 163
    From functions to bound methods
    >>> Door.open()
    Traceback (most recent call last):
    File "", line 1, in
    TypeError: open() missing 1 required positional argument: 'self'
    >>> Door.open(door1)
    >>> door1.status
    'open'
    >>> door1.__class__.__dict__['open']

    >>>

    View Slide

  62. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    62 163
    From functions to bound methods
    >>> Door.open()
    Traceback (most recent call last):
    File "", line 1, in
    TypeError: open() missing 1 required positional argument: 'self'
    >>> Door.open(door1)
    >>> door1.status
    'open'
    >>> door1.__class__.__dict__['open']

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

    View Slide

  63. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    63 163
    From functions to bound methods
    >>> Door.open()
    Traceback (most recent call last):
    File "", line 1, in
    TypeError: open() missing 1 required positional argument: 'self'
    >>> Door.open(door1)
    >>> door1.status
    'open'
    >>> door1.__class__.__dict__['open']

    >>> 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__']
    >>> door1.__class__.__dict__['open'].__get__

    >>>

    View Slide

  64. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    64 163
    From functions to bound methods
    >>> Door.open()
    Traceback (most recent call last):
    File "", line 1, in
    TypeError: open() missing 1 required positional argument: 'self'
    >>> Door.open(door1)
    >>> door1.status
    'open'
    >>> door1.__class__.__dict__['open']

    >>> 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__']
    >>> door1.__class__.__dict__['open'].__get__

    >>> door1.__class__.__dict__['open'].__get__(door1)
    >
    >>>

    View Slide

  65. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    65 163
    Python
    2.x
    Python
    2.x
    From functions to bound methods
    >>> door1.__class__.__dict__['open'].__get__(door1)
    >
    >>> door1.__class__.__dict__['open'].__get__(door1, Door)
    >
    >>>

    View Slide

  66. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    66 163
    Class methods
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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'
    >>> door1 = Door(1, 'closed')
    >>> door1.knock()
    Knock!
    >>> Door.knock()
    Knock!
    >>>
    part2/02.py

    View Slide

  67. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    67 163
    Class methods
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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'
    part2/03.py

    View Slide

  68. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    68 163
    >>> door1 = Door(1, 'closed')
    >>> door2 = Door(2, 'closed')
    >>>
    Class methods

    View Slide

  69. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    69 163
    >>> door1 = Door(1, 'closed')
    >>> door2 = Door(2, 'closed')
    >>> Door.colour
    'brown'
    >>> door1.colour
    'brown'
    >>> door2.colour
    'brown'
    >>>
    Class methods

    View Slide

  70. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    70 163
    >>> door1 = Door(1, 'closed')
    >>> door2 = Door(2, 'closed')
    >>> Door.colour
    'brown'
    >>> door1.colour
    'brown'
    >>> door2.colour
    'brown'
    >>> Door.paint('white')
    >>>
    Class methods

    View Slide

  71. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    71 163
    >>> door1 = Door(1, 'closed')
    >>> door2 = Door(2, 'closed')
    >>> Door.colour
    'brown'
    >>> door1.colour
    'brown'
    >>> door2.colour
    'brown'
    >>> Door.paint('white')
    >>> Door.colour
    'white'
    >>> door1.colour
    'white'
    >>> door2.colour
    'white'
    >>>
    Class methods

    View Slide

  72. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    72 163
    >>> door1 = Door(1, 'closed')
    >>> door2 = Door(2, 'closed')
    >>> Door.colour
    'brown'
    >>> door1.colour
    'brown'
    >>> door2.colour
    'brown'
    >>> Door.paint('white')
    >>> Door.colour
    'white'
    >>> door1.colour
    'white'
    >>> door2.colour
    'white'
    >>> door1.paint('yellow')
    >>>
    Class methods

    View Slide

  73. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    73 163
    >>> door1 = Door(1, 'closed')
    >>> door2 = Door(2, 'closed')
    >>> Door.colour
    'brown'
    >>> door1.colour
    'brown'
    >>> door2.colour
    'brown'
    >>> 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

    View Slide

  74. PART 3
    Delegation

    View Slide

  75. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    75 163
    Cat
    Specialization
    Cat can provide new features
    i.e. 'has whiskers'
    Cat performs some or all the tasks performed by Animal in a different way
    i.e. 'moves silently'
    Animal
    Cat has all the features of Animal
    i.e. 'moves'

    View Slide

  76. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    76 163
    Animal Cat
    Delegation
    Cat implements only 'new' or 'changed' features
    Cat delegates the remaining features to Animal

    View Slide

  77. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    77 163
    Composition: 'has'
    Car
    Engine
    Wheels
    turn_on()
    steer()
    get_color()

    View Slide

  78. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    78 163
    Inheritance: 'is'
    Animal
    Cat
    look()
    look()
    meow()

    View Slide

  79. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    79 163

    View Slide

  80. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    80 163
    Inheritance
    1
    2
    class SecurityDoor(Door):
    pass
    >>> sdoor = SecurityDoor(1, 'closed')
    >>>
    part3/01.py

    View Slide

  81. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    81 163
    Inheritance
    1
    2
    class SecurityDoor(Door):
    pass
    >>> sdoor = SecurityDoor(1, 'closed')
    >>> SecurityDoor.colour is Door.colour
    True
    >>> sdoor.colour is Door.colour
    True
    part3/01.py

    View Slide

  82. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    82 163
    Inheritance
    1
    2
    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
    part3/01.py

    View Slide

  83. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    83 163
    Inheritance
    1
    2
    class SecurityDoor(Door):
    pass
    >>> sdoor.__dict__
    {'number': 1, 'status': 'closed'}
    >>>
    part3/01.py

    View Slide

  84. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    84 163
    Inheritance
    1
    2
    class SecurityDoor(Door):
    pass
    >>> sdoor.__dict__
    {'number': 1, 'status': 'closed'}
    >>> sdoor.__class__.__dict__
    mappingproxy({'__doc__': None, '__module__': '__main__'})
    >>>
    part3/01.py

    View Slide

  85. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    85 163
    Inheritance
    1
    2
    class SecurityDoor(Door):
    pass
    >>> sdoor.__dict__
    {'number': 1, 'status': 'closed'}
    >>> sdoor.__class__.__dict__
    mappingproxy({'__doc__': None, '__module__': '__main__'})
    >>> Door.__dict__
    mappingproxy({'__dict__': ,
    'colour': 'yellow',
    'open': ,
    '__init__': ,
    '__doc__': None,
    'close': ,
    'knock': ,
    '__weakref__': ,
    '__module__': '__main__',
    'paint': })
    >>>
    part3/01.py

    View Slide

  86. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    86 163
    Inheritance
    1
    2
    class SecurityDoor(Door):
    pass
    >>> SecurityDoor.__bases__
    (,)
    >>>
    part3/01.py

    View Slide

  87. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    87 163
    Inheritance
    1
    2
    class SecurityDoor(Door):
    pass
    >>> SecurityDoor.__bases__
    (,)
    >>> sdoor.knock
    >
    >>>
    part3/01.py

    View Slide

  88. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    88 163
    Inheritance
    1
    2
    class SecurityDoor(Door):
    pass
    >>> SecurityDoor.__bases__
    (,)
    >>> sdoor.knock
    >
    >>> sdoor.__class__.__bases__[0].__dict__['knock'].__get__(sdoor)
    >
    >>>
    part3/01.py

    View Slide

  89. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    89 163
    Overriding
    1
    2
    3
    4
    5
    6
    7
    class SecurityDoor(Door):
    colour = 'grey'
    locked = True
    def open(self):
    if not self.locked:
    self.status = 'open'
    part3/02.py

    View Slide

  90. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    90 163
    Overriding
    1
    2
    3
    4
    5
    6
    7
    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': ,
    'colour': 'grey',
    'locked': True})
    >>>
    Overriding blocks implicit delegation
    part3/02.py

    View Slide

  91. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    91 163
    Calling the parent implementation
    1
    2
    3
    4
    5
    6
    7
    8
    class SecurityDoor(Door):
    colour = 'grey'
    locked = True
    def open(self):
    if self.locked:
    return
    Door.open(self)
    >>> sdoor = SecurityDoor(1, 'closed')
    >>>
    part3/03.py

    View Slide

  92. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    92 163
    Calling the parent implementation
    1
    2
    3
    4
    5
    6
    7
    8
    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'
    >>>
    part3/03.py

    View Slide

  93. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    93 163
    Calling the parent implementation
    1
    2
    3
    4
    5
    6
    7
    8
    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'
    >>>
    part3/03.py

    View Slide

  94. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    94 163
    Avoid strong coupling
    1
    2
    3
    4
    5
    6
    7
    8
    class SecurityDoor(Door):
    colour = 'grey'
    locked = True
    def open(self):
    if self.locked:
    return
    super().open()
    >>> sdoor = SecurityDoor(1, 'closed')
    >>> sdoor.status
    'closed'
    >>> sdoor.open()
    >>> sdoor.status
    'closed'
    >>> sdoor.locked = False
    >>> sdoor.open()
    >>> sdoor.status
    'open'
    >>>
    part3/04.py
    super() to the rescue!

    View Slide

  95. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    95 163
    Python
    2.x
    Python
    2.x
    Avoid strong coupling
    1
    2
    3
    4
    5
    6
    7
    8
    class SecurityDoor(Door):
    colour = 'grey'
    locked = True
    def open(self):
    if self.locked:
    return
    super(SecurityDoor, self).open(self)
    part3/04.py

    View Slide

  96. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    96 163
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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

    View Slide

  97. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    97 163
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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
    No way to get the status
    part3/05.py

    View Slide

  98. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    98 163
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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)
    Python magic to the rescue
    part3/06.py

    View Slide

  99. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    99 163
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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)
    Python magic to the rescue
    part3/07.py

    View Slide

  100. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    100 163
    Composed inheritance?
    1
    2
    3
    4
    5
    6
    class ComposedDoor:
    def __init__(self, number, status):
    self.door = Door(number, status)
    def __getattr__(self, attr):
    return getattr(self.door, attr)
    part3/08.py

    View Slide

  101. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    101 163
    Composed inheritance?
    1
    2
    3
    4
    5
    6
    class ComposedDoor:
    def __init__(self, number, status):
    self.door = Door(number, status)
    def __getattr__(self, attr):
    return getattr(self.door, attr)
    getattr() != __getattr__()
    part3/08.py

    View Slide

  102. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    102 163
    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']
    >>>

    View Slide

  103. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    103 163
    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']
    >>> l.append

    >>> a = l.append
    >>> a

    >>>

    View Slide

  104. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    104 163
    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']
    >>> l.append

    >>> a = l.append
    >>> a

    >>> b = getattr(l, 'append')
    >>> b

    >>>

    View Slide

  105. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    105 163
    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']
    >>> l.append

    >>> a = l.append
    >>> a

    >>> b = getattr(l, 'append')
    >>> b

    >>> a == b
    True
    >>>

    View Slide

  106. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    106 163
    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']
    >>> l.append

    >>> a = l.append
    >>> a

    >>> b = getattr(l, 'append')
    >>> b

    >>> a == b
    True
    >>> a is b
    False
    >>>

    View Slide

  107. PART 4
    Polymorphism

    View Slide

  108. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    108 163
    References
    >>> a = 5
    >>> a
    5
    >>>

    View Slide

  109. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    109 163
    References
    >>> a = 5
    >>> a
    5
    >>> type(a)

    >>> This was not declared!

    View Slide

  110. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    110 163
    References
    >>> a = 5
    >>> a
    5
    >>> type(a)

    >>> hex(id(a))
    '0x83fe540'
    >>>

    View Slide

  111. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    111 163
    References
    >>> a = 5
    >>> a
    5
    >>> type(a)

    >>> hex(id(a))
    '0x83fe540'
    >>> a = 'five'
    >>> a
    'five'
    >>>

    View Slide

  112. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    112 163
    References
    >>> a = 5
    >>> a
    5
    >>> type(a)

    >>> hex(id(a))
    '0x83fe540'
    >>> a = 'five'
    >>> a
    'five'
    >>> type(a)

    >>> hex(id(a))
    '0xb70d6560'
    >>>

    View Slide

  113. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    113 163
    References
    >>> a = 5
    >>> a
    5
    >>> type(a)

    >>> hex(id(a))
    '0x83fe540'
    >>> a = 'five'
    >>> a
    'five'
    >>> type(a)

    >>> hex(id(a))
    '0xb70d6560'
    >>>
    A strong type system: every variable has a type

    View Slide

  114. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    114 163
    References
    >>> a = 5
    >>> a
    5
    >>> type(a)

    >>> hex(id(a))
    '0x83fe540'
    >>> a = 'five'
    >>> a
    'five'
    >>> type(a)

    >>> hex(id(a))
    '0xb70d6560'
    >>>
    A strong type system: every variable has a type
    A dynamic type system: the type changes with the content

    View Slide

  115. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    115 163
    Every variable is a reference
    1
    2
    def echo(a):
    return a
    part4/01.py

    View Slide

  116. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    116 163
    Every variable is a reference
    1
    2
    def echo(a):
    return a
    >>> echo(5)
    5
    >>> echo('five')
    'five'
    >>>
    part4/01.py

    View Slide

  117. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    117 163
    Every variable is a reference
    1
    2
    def echo(a):
    return a
    >>> echo(5)
    5
    >>> echo('five')
    'five'
    >>>
    Both are references
    part4/01.py

    View Slide

  118. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    118 163
    What is polymorphism?
    >>> 5 + 6
    11
    >>> 5.5 + 6.6
    12.1
    >>>

    View Slide

  119. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    119 163
    >>> 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?

    View Slide

  120. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    120 163
    >>> 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 "", line 1, in
    TypeError: unsupported operand type(s) for +: 'dict' and 'dict'
    >>>
    What is polymorphism?

    View Slide

  121. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    121 163
    >>> l = [1, 2, 3]
    >>> len(l)
    3
    >>>
    What is polymorphism?

    View Slide

  122. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    122 163
    >>> l = [1, 2, 3]
    >>> len(l)
    3
    >>> s = "Just a sentence"
    >>> len(s)
    15
    >>> d = {'a': 1, 'b': 2}
    >>> len(d)
    2
    >>>
    What is polymorphism?

    View Slide

  123. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    123 163
    >>> l = [1, 2, 3]
    >>> len(l)
    3
    >>> s = "Just a sentence"
    >>> len(s)
    15
    >>> d = {'a': 1, 'b': 2}
    >>> len(d)
    2
    >>> i = 5
    >>> len(i)
    Traceback (most recent call last):
    File "", line 1, in
    TypeError: object of type 'int' has no len()
    >>>
    What is polymorphism?

    View Slide

  124. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    124 163
    >>> l = [1, 2, 3]
    >>> len(l)
    3
    >>> s = "Just a sentence"
    >>> len(s)
    15
    >>> d = {'a': 1, 'b': 2}
    >>> len(d)
    2
    >>> i = 5
    >>> len(i)
    Traceback (most recent call last):
    File "", line 1, in
    TypeError: object of type 'int' has no len()
    >>> l.__len__()
    3
    >>> s.__len__()
    15
    >>> d.__len__()
    2
    >>> i.__len__()
    Traceback (most recent call last):
    File "", line 1, in
    AttributeError: 'int' object has no attribute '__len__'
    >>>
    What is polymorphism?

    View Slide

  125. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    125 163
    Polymorphism is based on delegation
    >>> [1,2,3].__add__([4,5,6])
    [1, 2, 3, 4, 5, 6]
    >>>

    View Slide

  126. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    126 163
    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__', '__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']
    >>>

    View Slide

  127. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    127 163
    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__', '__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']
    >>> 1 in [1,2,3]
    True
    >>> [1,2,3].__contains__(1)
    True
    >>> 6 in [1,2,3]
    False
    >>> [1,2,3].__contains__(6)
    False
    >>>

    View Slide

  128. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    128 163
    Polymorphism is based on delegation
    1
    2
    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]
    >>>
    part4/02.py

    View Slide

  129. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    129 163
    Polymorphism is based on delegation
    1
    2
    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 "", line 1, in
    File "", line 2, in sum
    TypeError: can only concatenate list (not "int") to list
    >>>
    part4/02.py

    View Slide

  130. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    130 163
    Polymorphism in action
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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()
    part4/03.py

    View Slide

  131. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    131 163
    Polymorphism in action
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    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"
    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
    part4/03.py

    View Slide

  132. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    132 163
    Polymorphism in action
    >>> door = Door()
    >>> bool_door = BooleanDoor()
    >>> room = Room(door)
    >>> bool_room = Room(bool_door)
    >>>

    View Slide

  133. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    133 163
    Polymorphism in action
    >>> 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
    >>>

    View Slide

  134. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    134 163
    Polymorphism in action
    >>> 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
    >>>

    View Slide

  135. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    135 163
    “Ask for permission” style
    1
    2
    3
    4
    if hasattr(someobj, 'open'):
    [...]
    else:
    [...]

    View Slide

  136. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    136 163
    “Ask for forgiveness” style
    1
    2
    3
    4
    if hasattr(someobj, 'open'):
    [...]
    else:
    [...]
    1
    2
    3
    4
    5
    try:
    someobj.open()
    [...]
    except AttributeError:
    [...]

    View Slide

  137. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    137 163
    “Ask for forgiveness” style
    1
    2
    3
    4
    if hasattr(someobj, 'open'):
    [...]
    else:
    [...]
    1
    2
    3
    4
    5
    try:
    someobj.open()
    [...]
    except AttributeError:
    [...]
    It 'has' the attribute
    It behaves like it has the attribute

    View Slide

  138. PART 5
    Metaclasses

    View Slide

  139. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    139 163
    Everything is an object (again)
    >>> a = 5
    >>>

    View Slide

  140. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    140 163
    Everything is an object (again)
    >>> a = 5
    >>> type(a)

    >>> a.__class__

    >>>

    View Slide

  141. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    141 163
    Everything is an object (again)
    >>> a = 5
    >>> type(a)

    >>> a.__class__

    >>> a.__class__.__bases__
    (,)
    >>> object.__bases__
    ()
    >>>

    View Slide

  142. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    142 163
    Everything is an object (again)
    a
    int
    object
    >>> a = 5
    >>> type(a)

    >>> a.__class__

    >>> a.__class__.__bases__
    (,)
    >>> object.__bases__
    ()
    >>>

    View Slide

  143. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    143 163
    a
    int
    object
    >>> a = 5
    >>> type(a)

    >>> a.__class__

    >>> a.__class__.__bases__
    (,)
    >>> object.__bases__
    ()
    >>>
    Everything is an object (again)
    'int' inherits from (its base is) 'object'
    'a' is an instance of (its type is) 'int'

    View Slide

  144. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    144 163
    Where classes come from
    >>> type(a)

    >>>

    View Slide

  145. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    145 163
    Where classes come from
    >>> type(a)

    >>> type(int)

    >>>

    View Slide

  146. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    146 163
    Where classes come from
    >>> type(a)

    >>> type(int)

    >>> type(float)

    >>> type(dict)

    >>>

    View Slide

  147. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    147 163
    >>> type(a)

    >>> type(int)

    >>> type(float)

    >>> type(dict)

    >>>
    a
    object
    Everything is an object (again)
    'int' inherits from (its base is) 'object'
    'int' is an instance of (its type is) 'type'
    type
    int

    View Slide

  148. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    148 163
    >>> type(a)

    >>> type(int)

    >>> type(float)

    >>> type(dict)

    >>>
    a
    int
    object
    Everything is an object (again)
    'int' finds here attributes and methods
    'int' description as a class is here
    type

    View Slide

  149. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    149 163
    Food for thought
    object type
    >>> type(object)

    >>> type.__bases__
    (,)
    >>>

    View Slide

  150. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    150 163
    Fatality
    >>> type(type)

    object type

    View Slide

  151. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    151 163
    Python
    2.x
    Python
    2.x
    >>> type(type)

    Fatality

    View Slide

  152. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    152 163
    Metaclasses
    1
    2
    3
    4
    5
    class MyType(type):
    pass
    class MySpecialClass(metaclass=MyType):
    pass
    part5/01.py

    View Slide

  153. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    153 163
    Python
    2.x
    Python
    2.x
    1
    2
    3
    4
    5
    class MyType(type):
    pass
    class MySpecialClass(object):
    __metaclass__ = MyType
    part5/01.py

    View Slide

  154. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    154 163
    Metaclasses
    >>> msp = MySpecialClass()
    >>>
    1
    2
    3
    4
    5
    class MyType(type):
    pass
    class MySpecialClass(metaclass=MyType):
    pass
    part5/01.py

    View Slide

  155. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    155 163
    Metaclasses
    >>> msp = MySpecialClass()
    >>> type(msp)

    >>>
    1
    2
    3
    4
    5
    class MyType(type):
    pass
    class MySpecialClass(metaclass=MyType):
    pass
    part5/01.py

    View Slide

  156. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    156 163
    Metaclasses
    >>> msp = MySpecialClass()
    >>> type(msp)

    >>> type(MySpecialClass)

    >>>
    1
    2
    3
    4
    5
    class MyType(type):
    pass
    class MySpecialClass(metaclass=MyType):
    pass
    part5/01.py

    View Slide

  157. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    157 163
    Metaclasses
    >>> msp = MySpecialClass()
    >>> type(msp)

    >>> type(MySpecialClass)

    >>> MySpecialClass.__bases__
    (,)
    >>>
    1
    2
    3
    4
    5
    class MyType(type):
    pass
    class MySpecialClass(metaclass=MyType):
    pass
    part5/01.py

    View Slide

  158. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    158 163
    1
    2
    3
    4
    5
    6
    7
    8
    9
    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
    Metaclasses in action: singleton
    part5/02.py

    View Slide

  159. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    159 163
    Metaclasses in action: singleton
    1
    2
    3
    4
    5
    6
    7
    8
    9
    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()
    >>>
    part5/02.py

    View Slide

  160. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    160 163
    Metaclasses in action: singleton
    1
    2
    3
    4
    5
    6
    7
    8
    9
    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
    >>>
    part5/02.py

    View Slide

  161. Deep inside Object-oriented Python – PyConIE 2014 – lgiordani.com - CC BY-SA 4.0
    161 163
    Metaclasses in action: singleton
    1
    2
    3
    4
    5
    6
    7
    8
    9
    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'
    >>>
    part5/02.py

    View Slide

  162. SOME
    LINKS
    The original posts
    http://lgiordani.com/blog/categories/python3/
    Some links about Python OOP
    http://goo.gl/UBdJDT

    View Slide

  163. THANK YOU!
    Any comment, correction or
    contribution is warmly welcome.
    Feel free to contact me.
    https://github.com/
    lgiordani
    https://twitter.com/
    tw_lgiordani
    https://plus.google.com/u/
    LeonardoGiordani
    The Digital Cat
    http://lgiordani.com

    View Slide