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. 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
  2. 3.

    || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||

     PABLO ENFEDAQUE VIDAL ||  @pablitoev56  || Let'ʹs  review  5  key  concepts
  3. 4.

    || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||

     PABLO ENFEDAQUE VIDAL ||  @pablitoev56  || Immutable objects  have read-­‐‑only value 1st key  concept
  4. 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
  5. 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
  6. 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
  7. 8.

    || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||

     PABLO ENFEDAQUE VIDAL ||  @pablitoev56  || Names (attrs.)  are  pointers and  = copies  the  reference 2nd key  concept
  8. 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]
  9. 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]
  10. 11.

    || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||

     PABLO ENFEDAQUE VIDAL ||  @pablitoev56  || Mutable objects  provide in-­‐‑place modifiers 3rd key  concept
  11. 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
  12. 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
  13. 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
  14. 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]
  15. 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]
  16. 17.

    || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||

     PABLO ENFEDAQUE VIDAL ||  @pablitoev56  || Python  code  is  interpreted  at   import  time 4th  key  concept
  17. 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
  18. 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
  19. 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
  20. 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]
  21. 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]
  22. 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]
  23. 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]
  24. 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]
  25. 26.

    || MUTABLE VS.  IMMUTABLE OBJECTS || PYCON ES  2015 ||

     PABLO ENFEDAQUE VIDAL ||  @pablitoev56  || How  to  avoid  these  issues?
  26. 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
  27. 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
  28. 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]
  29. 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]
  30. 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
  31. 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