Mutable vs. Immutable objects

6acd43823845318dac6fb44355b89cc8?s=47 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.

6acd43823845318dac6fb44355b89cc8?s=128

Pablo E

November 21, 2015
Tweet

Transcript

  1. { MUTABLE VS.   IMMUTABLE OBJECTS PYCON ES  2015 PABLO

    ENFEDAQUE VIDAL @pablitoev56
  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
  3. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||

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

     PABLO ENFEDAQUE VIDAL ||  @pablitoev56  || Immutable objects  have read-­‐‑only value 1st key  concept
  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
  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
  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
  8. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||

     PABLO ENFEDAQUE VIDAL ||  @pablitoev56  || Names (attrs.)  are  pointers and  = copies  the  reference 2nd key  concept
  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]
  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]
  11. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||

     PABLO ENFEDAQUE VIDAL ||  @pablitoev56  || Mutable objects  provide in-­‐‑place modifiers 3rd key  concept
  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
  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
  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
  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]
  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]
  17. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||

     PABLO ENFEDAQUE VIDAL ||  @pablitoev56  || Python  code  is  interpreted  at   import  time 4th  key  concept
  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
  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
  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
  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]
  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]
  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]
  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]
  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]
  26. || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||

     PABLO ENFEDAQUE VIDAL ||  @pablitoev56  || How  to  avoid  these  issues?
  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
  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
  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]
  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]
  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
  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