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

Python Wats: Uncovering Odd Behavior - Amy Hanlon

Python Wats: Uncovering Odd Behavior - Amy Hanlon

Some behavior of the Python interpreter is really weird. Have you ever wondered why you tend to get bugs when you have mutable default arguments? Or why you shouldn't use the is statement to determine equality of integers? Or why tuples are greater than strings but strings are greater than lists? Let's investigate these odd behaviors, and more, to learn what's really going on. You'll leave this talk with some practical knowledge of how to avoid common bugs and some fun Python trivia.

PyGotham 2014

August 16, 2014
Tweet

More Decks by PyGotham 2014

Other Decks in Programming

Transcript

  1. >  a  =  256   >  b  =  256  

    >  a  is  b   ??? Trivia
  2. >  a  =  256   >  b  =  256  

    >  a  is  b   True Trivia
  3. >  a  =  257   >  b  =  257  

    >  a  is  b   ??? Trivia
  4. >  a  =  257   >  b  =  257  

    >  a  is  b   False Trivia
  5. >  a  =  257;  b  =  257   >  a

     is  b   True Trivia
  6. a Why? -­‐5 … 255 256 … b >  a

     =  256   >  b  =  256   !
  7. a Why? -­‐5 … 255 256 … b >  a

     =  256   >  b  =  256   >  a  is  b   True
  8. a Why? … 255 256 … 257 257 b >

     a  =  257   >  b  =  257   !
  9. a Why? … 255 256 … 257 257 b >

     a  =  257   >  b  =  257   >  a  is  b   False
  10. >  a  =  257   >  b  =  257  

    >  id(a)  ==  id(b)   False Why?
  11. • Use == instead of is  to compare values •

    Exceptions: • x  is  None   • tests for identity Tips
  12. >  faves  =  ["cats",  "dragons"]   >  temp  =  faves

      >  temp.append("rainbows")   ! Trivia
  13. >  faves  =  ["cats",  "dragons"]   >  temp  =  faves

      >  temp.append("rainbows")   >  temp   ??? Trivia
  14. >  faves  =  ["cats",  "dragons"]   >  temp  =  faves

      >  temp.append("rainbows")   >  temp   ["cats",  "dragons",  "rainbows"] Trivia
  15. >  faves  =  ["cats",  "dragons"]   >  temp  =  faves

      >  temp.append("rainbows")   >  faves   ??? Trivia
  16. >  faves  =  ["cats",  "dragons"]   >  temp  =  faves

      >  temp.append("rainbows")   >  faves   ["cats",  "dragons",  "rainbows"] Trivia
  17. >  temp  =  []   >  for  element  in  faves:

                 temp.append(element) Tip: Shallow Copy
  18. >  faves  =  [["cats",  "dragons"]]   >  temp  =  faves[:]

      >  temp[0].append("rainbows")   ! Tip: Deep Copy
  19. >  faves  =  [["cats",  "dragons"]]   >  temp  =  faves[:]

      >  temp[0].append("rainbows")   >  faves   ??? Tip: Deep Copy
  20. >  faves  =  [["cats",  "dragons"]]   >  temp  =  faves[:]

      >  temp[0].append("rainbows")   >  faves   [["cats",  "dragons",  "rainbows"]] Tip: Deep Copy
  21. • For arbitrarily-nested lists, make deep copies ! >  import

     copy   >  temp  =  copy.deepcopy(faves) Tip: Deep Copy
  22. def  append_cat(l=[]):          l.append(‘cat’)      

       return  l   ! >  append_cat()   ???   ! Trivia
  23. def  append_cat(l=[]):          l.append(‘cat’)      

       return  l   ! >  append_cat()   [‘cat’]   ! Trivia
  24. def  append_cat(l=[]):          l.append(‘cat’)      

       return  l   ! >  append_cat()   [‘cat’]   >  append_cat()   ??? Trivia
  25. def  append_cat(l=[]):          l.append(‘cat’)      

       return  l   ! >  append_cat()   [‘cat’]   >  append_cat()   [‘cat’,  ‘cat’] Trivia
  26. def  append_cat(l=[]):          l.append(‘cat’)      

       return  l   ! >  append_cat.func_defaults   ???   Why?
  27. def  append_cat(l=[]):          l.append(‘cat’)      

       return  l   ! >  append_cat.func_defaults   ([],)   Why?
  28. def  append_cat(l=[]):          l.append('cat')      

       return  l   ! >  append_cat()   >  append_cat.func_defaults   ??? Why?
  29. def  append_cat(l=[]):          l.append('cat')      

       return  l   ! >  append_cat()   >  append_cat.func_defaults   (['cat'],) Why?
  30. def  append_cat(l=None):          if  l  is  None:

                     l  =  []   ! Tip: Use None
  31. def  append_cat(l=None):          if  l  is  None:

                     l  =  []          l.append(‘cat')          return  l Tip: Use None
  32. def  sorting_hat(student,  cache={}):          if  student  in

     cache:                  print  "Used  cache!"                  return  cache[student]          else:   ! ! Tip: Take Advantage!
  33. def  sorting_hat(student,  cache={}):          if  student  in

     cache:                  print  "Used  cache!"                  return  cache[student]          else:                  house  =  slow_alg(student)                  cache[student]  =  house                  return  house Tip: Take Advantage!
  34. >  sorting_hat('Amy  Hanlon')   'Ravenclaw'   >  sorting_hat('Amy  Hanlon')  

    Used  cache!   ‘Ravenclaw'   ! Tip: Take Advantage!
  35. >  sorting_hat('Amy  Hanlon')   'Ravenclaw'   >  sorting_hat('Amy  Hanlon')  

    Used  cache!   ‘Ravenclaw'   >  sorting_hat.func_defaults   ({'Amy  Hanlon':  'Ravenclaw'},) Tip: Take Advantage!
  36. >  a  =  1   >  def  foo():    

         return  a   ! ! Trivia
  37. >  a  =  1   >  def  foo():    

         return  a   ! >  foo()   ??? Trivia
  38. >  a  =  1   >  def  foo():    

         return  a   ! >  foo()   1 Trivia
  39. Namespaces! ! • locals()   • globals()      

     #  {'a'  :  1}   • __builtins__ Why?
  40. >  a  =  1   >  def  foo():    

         return  a   ! >  foo()   1 Trivia
  41. >  a  =  1   >  def  foo():    

         a  +=  1          return  a   ! >  foo()   ??? Trivia
  42. >  a  =  1   >  def  foo():    

         a  +=  1          return  a   ! >  foo()   UnboundLocalError:  local   variable  'a'  referenced  before   assignment Trivia
  43. “When you make an assignment to a variable in a

    scope, that variable becomes local to that scope.” Why?
  44. Why? >  a  =  1   >  def  foo():  

           #  a  +=  1          a  =  a  +  1          return  a
  45. >  a  =  1   >  def  foo():    

         global  a          a  +=  1          return  a   >  foo()   2   >  a   2 Tip: Use global
  46. >  def  foo(a):          a  +=  1

             return  a   >  a  =  1   >  a  =  foo(a)   2 Tip: Don’t Use global