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

Mutable vs. Immutable objects

Pablo E
November 21, 2015

Mutable vs. Immutable objects

Typical errors when dealing with mutable objects and not having a full understanding of how certain Python internals work.

pybcn meetup and PyCon ES 2015 talk.

Pablo E

November 21, 2015
Tweet

More Decks by Pablo E

Other Decks in Programming

Transcript

  1. {
    MUTABLE VS.  
    IMMUTABLE OBJECTS
    PYCON ES  2015
    PABLO ENFEDAQUE VIDAL
    @pablitoev56

    View Slide

  2. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    Typical  errors  when  dealing  
    with  mutable  objects  and  not  
    having  a  full  understanding  of  
    how  certain  Python  internals
    work
    Alternative  talk  title

    View Slide

  3. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    Let'ʹs  review  5  key  concepts

    View Slide

  4. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    Immutable objects  have
    read-­‐‑only value
    1st key  concept

    View Slide

  5. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    Immutable objects  have
    read-­‐‑only value
    Numbers,  strings,  booleans,  tuples...
    1st key  concept

    View Slide

  6. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    read-­‐‑only value
    >>> integer_A = integer_B = 7
    >>> print id(integer_A) # id function returns unique object id
    140418098411560
    >>> print id(integer_B)
    140418098411560
    >>> integer_A = 56
    >>> integer_B = 13
    >>> print id(integer_A)
    140418098412338
    >>> print id(integer_B)
    140418098411416

    View Slide

  7. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    different  object  id
    >>> integer_A = integer_B = 7
    >>> print id(integer_A) # id function returns unique object id
    140418098411560
    >>> print id(integer_B)
    140418098411560
    >>> integer_A = 56
    >>> integer_B = 13
    >>> print id(integer_A)
    140418098412360
    >>> print id(integer_B)
    140418098411416

    View Slide

  8. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    Names (attrs.)  are  pointers
    and  = copies  the  reference
    2nd key  concept

    View Slide

  9. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    = copies  the  reference
    >>> list_A = list_B = []
    >>> print id(list_A)
    4404555072
    >>> print id(list_B)
    4404555072
    >>> list_A.append(7)
    >>> list_C = [13, 56]
    >>> list_B.extend(list_C)
    >>> print list_A
    [7, 13, 56]
    >>> print list_B
    [7, 13, 56]

    View Slide

  10. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    in-­‐‑place changes  of  the  same  object
    >>> list_A = list_B = []
    >>> print id(list_A)
    4404555072
    >>> print id(list_B)
    4404555072
    >>> list_A.append(7)
    >>> list_C = [13, 56]
    >>> list_B.extend(list_C)
    >>> print list_A
    [7, 13, 56]
    >>> print list_B
    [7, 13, 56]

    View Slide

  11. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    Mutable objects  provide
    in-­‐‑place modifiers
    3rd key  concept

    View Slide

  12. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    Mutable objects  provide
    in-­‐‑place modifiers
    list.append(),  dict.update(),  set.add()...
    3rd key  concept

    View Slide

  13. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    What  is  the  expected result?
    >>> class Accumulator(object):
    ... accum_stuff = []
    ... def accumulate(self, stuff):
    ... self.accum_stuff.append(stuff)
    ...
    >>> instance_A = Accumulator()
    >>> instance_B = Accumulator()
    >>> print id(instance_A), id(instance_B)
    4405198608 4405211664
    >>> instance_A.accumulate(7)
    >>> instance_A.accumulate(13)
    >>> print instance_B.accum_stuff

    View Slide

  14. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    And  what  are  we  gonna get  here?
    >>> class Accumulator(object):
    ... accum_stuff = []
    ... def accumulate(self, stuff):
    ... self.accum_stuff.append(stuff)
    ...
    >>> instance_A = Accumulator()
    >>> instance_B = Accumulator()
    >>> print id(instance_A), id(instance_B)
    4405198608 4405211664
    >>> instance_A.accumulate(7)
    >>> instance_A.accumulate(13)
    >>> print instance_B.accum_stuff
    [7, 13]
    >>> print id(instance_B.accum_stuff), id(instance_A.accum_stuff)
    4405148272 4405148272
    >>> print id(Accumulator.accum_stuff), Accumulator.accum_stuff

    View Slide

  15. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    in-­‐‑place changes  of  the  same  object
    >>> class Accumulator(object):
    ... accum_stuff = []
    ... def accumulate(self, stuff):
    ... self.accum_stuff.append(stuff)
    ...
    >>> instance_A = Accumulator()
    >>> instance_B = Accumulator()
    >>> print id(instance_A), id(instance_B)
    4405198608 4405211664
    >>> instance_A.accumulate(7)
    >>> instance_A.accumulate(13)
    >>> print instance_B.accum_stuff
    [7, 13]
    >>> print id(instance_B.accum_stuff), id(instance_A.accum_stuff)
    4405148272 4405148272
    >>> print id(Accumulator.accum_stuff), Accumulator.accum_stuff
    4405148272 [7, 13]

    View Slide

  16. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    object  created  at  import  time
    >>> class Accumulator(object):
    ... accum_stuff = []
    ... def accumulate(self, stuff):
    ... self.accum_stuff.append(stuff)
    ...
    >>> instance_A = Accumulator()
    >>> instance_B = Accumulator()
    >>> print id(instance_A), id(instance_B)
    4405198608 4405211664
    >>> instance_A.accumulate(7)
    >>> instance_A.accumulate(13)
    >>> print instance_B.accum_stuff
    [7, 13]
    >>> print id(instance_B.accum_stuff), id(instance_A.accum_stuff)
    4405148272 4405148272
    >>> print id(Accumulator.accum_stuff), Accumulator.accum_stuff
    4405148272 [7, 13]

    View Slide

  17. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    Python  code  is  interpreted  at  
    import  time
    4th  key  concept

    View Slide

  18. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    Python  code  is  interpreted  at  
    import  time
    Interpreted  means  executed
    4th  key  concept

    View Slide

  19. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    Python  code  is  interpreted  at  
    import  time
    Interpreted  means  executed
    This  includes  objects  creation
    4th  and 5th  key  concepts

    View Slide

  20. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    What  is  the  expected result?
    >>> def accum_power(x, y, accum=[]):
    ... accum.append(x ** y)
    ... return accum
    ...
    >>> accum = accum_power(2, 3)
    >>> accum = accum_power(2, 4, accum)
    >>> print id(accum), accum
    4405203672 [8, 16]
    >>> accum3 = accum_power(3, 3)
    >>> accum3 = accum_power(3, 4, accum3)
    >>> print id(accum3), accum3

    View Slide

  21. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    And  now?
    >>> def accum_power(x, y, accum=[]):
    ... accum.append(x ** y)
    ... return accum
    ...
    >>> accum = accum_power(2, 3)
    >>> accum = accum_power(2, 4, accum)
    >>> print id(accum), accum
    4405203672 [8, 16]
    >>> accum3 = accum_power(3, 3)
    >>> accum3 = accum_power(3, 4, accum3)
    >>> print id(accum3), accum3
    4405203672 [8, 16, 27, 81]
    >>> print id(accum_power.func_defaults[0])
    >>> print accum_power.func_defaults[0]

    View Slide

  22. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    why?
    >>> def accum_power(x, y, accum=[]):
    ... accum.append(x ** y)
    ... return accum
    ...
    >>> accum = accum_power(2, 3)
    >>> accum = accum_power(2, 4, accum)
    >>> print id(accum), accum
    4405203672 [8, 16]
    >>> accum3 = accum_power(3, 3)
    >>> accum3 = accum_power(3, 4, accum3)
    >>> print id(accum3), accum3
    4405203672 [8, 16, 27, 81]
    >>> print id(accum_power.func_defaults[0])
    4405203672 # func_defaults contains argument's default value
    >>> print accum_power.func_defaults[0]
    [8, 16, 27, 81]

    View Slide

  23. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    again,  object  created  at  import  time
    >>> def accum_power(x, y, accum=[]):
    ... accum.append(x ** y)
    ... return accum
    ...
    >>> accum = accum_power(2, 3)
    >>> accum = accum_power(2, 4, accum)
    >>> print id(accum), accum
    4405203672 [8, 16]
    >>> accum3 = accum_power(3, 3)
    >>> accum3 = accum_power(3, 4, accum3)
    >>> print id(accum3), accum3
    4405203672 [8, 16, 27, 81]
    >>> print id(accum_power.func_defaults[0])
    4405203672 # func_defaults contains argument's default value
    >>> print accum_power.func_defaults[0]
    [8, 16, 27, 81]

    View Slide

  24. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    there  is  even  more
    >>> def accum_power(x, y, accum=[]):
    ... accum.append(x ** y)
    ... return accum
    ...
    >>> accum = []
    >>> accum_power(5, 6, accum)
    [15625]
    >>> print accum
    [15625]
    >>> accum_power(7, 8, accum)
    [15625, 5764801]
    >>> print accum
    [15625, 5764801]

    View Slide

  25. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    did  we  say  pointers &  references?
    >>> def accum_power(x, y, accum=[]):
    ... accum.append(x ** y)
    ... return accum
    ...
    >>> accum = []
    >>> accum_power(5, 6, accum)
    >>> print accum
    [15625]
    >>> accum_power(7, 8, accum)
    >>> print accum
    [15625, 5764801]

    View Slide

  26. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    How  to  avoid  these  issues?

    View Slide

  27. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    create  new  list when  needed
    >>> class Accumulator(object):
    ... def __init__(self):
    ... self.accum_stuff = []
    ... def accumulate(self, stuff):
    ... self.accum_stuff.append(stuff)
    ...
    >>> instance_A = Accumulator()
    >>> instance_B = Accumulator()
    >>> print id(instance_A), id(instance_B)
    4405198608 4405211664
    >>> instance_A.accumulate(7)
    >>> instance_A.accumulate(13)
    >>> print instance_B.accum_stuff
    [13]
    >>> print id(instance_B.accum_stuff), id(instance_A.accum_stuff)
    4405148272 4405149901

    View Slide

  28. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    the  list  is  an  instance  attribute
    >>> class Accumulator(object):
    ... def __init__(self):
    ... self.accum_stuff = []
    ... def accumulate(self, stuff):
    ... self.accum_stuff.append(stuff)
    ...
    >>> instance_A = Accumulator()
    >>> instance_B = Accumulator()
    >>> print id(instance_A), id(instance_B)
    4405198608 4405211664
    >>> instance_A.accumulate(7)
    >>> instance_A.accumulate(13)
    >>> print instance_B.accum_stuff
    [13]
    >>> print id(instance_B.accum_stuff), id(instance_A.accum_stuff)
    4405148272 4405149901

    View Slide

  29. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    create  new  list when  needed
    >>> def accum_power(x, y, accum=None):
    ... if accum is None:
    ... accum = []
    ... accum.append(x ** y)
    ... return accum
    ...
    >>> accum = accum_power(2, 3)
    >>> accum = accum_power(2, 4, accum)
    >>> print id(accum), accum
    4405203672 [8, 16]
    >>> accum3 = accum_power(3, 3)
    >>> accum3 = accum_power(3, 4, accum3)
    >>> print id(accum3), accum3
    4405200813 [27, 81]

    View Slide

  30. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    create  new  list when  needed
    >>> def accum_power(x, y, accum=None):
    ... if accum is None:
    ... accum = []
    ... accum.append(x ** y)
    ... return accum
    ...
    >>> accum = accum_power(2, 3)
    >>> accum = accum_power(2, 4, accum)
    >>> print id(accum), accum
    4405203672 [8, 16]
    >>> accum3 = accum_power(3, 3)
    >>> accum3 = accum_power(3, 4, accum3)
    >>> print id(accum3), accum3
    4405200813 [27, 81]

    View Slide

  31. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    >
    Shallow  copy  uses  the  reference  to  the  object
    > Assignment,  constructor  by  copy,  arguments  in  function  calls
    > Be  aware  of  it!
    >
    Class  attributes  remain  in  the  class
    > Create  instance  mutable  attributes  in  __init__
    >
    Functions  default  values  remain  in  the  function
    > Create  mutable  default  values  inside  the  function
    to  sum  up

    View Slide

  32. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||  PABLO ENFEDAQUE VIDAL ||  @pablitoev56  ||
    Q&A
    That'ʹs  all  folks!
    Slides:  
    https://speakerdeck.com/pablito56/mutable
    -­‐‑vs-­‐‑immutable-­‐‑objects

    View Slide