Allison Kaptur - Exploring is never boring: understanding CPython without reading the code

Allison Kaptur - Exploring is never boring: understanding CPython without reading the code

Have you started to read the source code of CPython but not gotten as far as you wanted? Maybe you want to understand more about CPython but don't know where to begin. I'll present a number of strategies for getting more familiar with Python under the hood that go beyond "just read it!" This talk isn't about contributing - it's about getting into the code base and discovering interesting things.

https://us.pycon.org/2015/schedule/presentation/333/

D5710b3bca38f1233274b4cbc523dc4b?s=128

PyCon 2015

April 18, 2015
Tweet

Transcript

  1. Exploring*is*Never*Boring

  2. @akaptur

  3. Exploring*is*Never*Boring Understanding+CPython+without+ reading+the+code

  4. Why$do$this? !

  5. Contribu)ng

  6. h"ps:/ /docs.python.org/devguide/

  7. "Read&the&code!"

  8. None
  9. None
  10. Not$reading$the$code

  11. Strategies Observa(on Experimenta+on

  12. Strategy(1:(Observa/on "Code&is&not&literature&and&we&are&not&readers.&Rather,& interes4ng&pieces&of&code&are&specimens&and&we&are& naturalists." —"Peter"Seibel,"Code"is"not"literature

  13. None
  14. How$to$observe

  15. Tools%for%observa,on:%inspect >>> import random >>> import inspect >>> print inspect.getsource(random.choice)

    def choice(self, seq): """Choose a random element from a non-empty sequence.""" return seq[int(self.random() * len(seq))] # raises IndexError if seq is empty
  16. Tools%for%observa,on:%inspect >>> import random >>> import inspect >>> print inspect.getsource(random.choice)

    def choice(self, seq): """Choose a random element from a non-empty sequence.""" return seq[int(self.random() * len(seq))] # raises IndexError if seq is empty >>> print inspect.getsource(list.append) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 701, in getsource lines, lnum = getsourcelines(object) File "/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 690, in getsourcelines lines, lnum = findsource(object) File "/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 526, in findsource file = getfile(object) File "/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 420, in getfile 'function, traceback, frame, or code object'.format(object)) TypeError: <method 'append' of 'list' objects> is not a module, class, method, function, traceback, frame, or code object >>> # :( github.com/punchagan/cinspect
  17. Tools%for%observa,on:%history%&% changelogs

  18. Tools%for%observa,on:%history%&%changelogs hg blame Python/ceval.c hg log -r ### -p

  19. Tools%for%observa,on:%internal% structure

  20. Tools%for%observa,on:%internal%structure >>> False is False is False

  21. Tools%for%observa,on:%internal%structure >>> (False is False) is False

  22. Tools%for%observa,on:%internal%structure >>> False is False is False True

  23. Tools%for%observa,on:%internal%structure >>> False is False is False True >>> a

    < b < c True
  24. Tools%for%observa,on:%internal%structure 1 0 LOAD_NAME 0 (False) 3 LOAD_NAME 0 (False)

    6 DUP_TOP 7 ROT_THREE 8 COMPARE_OP 8 (is) 11 JUMP_IF_FALSE_OR_POP 23 14 LOAD_NAME 0 (False) 17 COMPARE_OP 8 (is) 20 JUMP_FORWARD 2 (to 25) >> 23 ROT_TWO 24 POP_TOP >> 25 POP_TOP 26 LOAD_CONST 0 (None) 29 RETURN_VALUE
  25. Tools%for%observa,on:%internal%structure 1 0 LOAD_NAME 0 (a) 3 LOAD_NAME 1 (b)

    6 DUP_TOP 7 ROT_THREE 8 COMPARE_OP 0 (<) 11 JUMP_IF_FALSE_OR_POP 23 14 LOAD_NAME 2 (c) 17 COMPARE_OP 0 (<) 20 JUMP_FORWARD 2 (to 25) >> 23 ROT_TWO 24 POP_TOP >> 25 POP_TOP 26 LOAD_CONST 0 (None) 29 RETURN_VALUE
  26. Strategy(2:(Experimenta1on

  27. None
  28. Tools%for%science:%measurements e.g.$%meit $ python -m timeit -s "li = range(100)"

    "li.sort(reverse=True)" 1000000 loops, best of 3: 1.75 usec per loop $ python -m timeit -s "li = range(100)" "sorted(li, reverse=True)" 100000 loops, best of 3: 2.46 usec per loop
  29. Tools%for%science:%write%tests

  30. Tools%for%science:%simula0ons

  31. Observa(on+&+Experimenta(on+>+Reading+ the+code • Introspect+it • Examine+it+cri1cally • Watch+it+evolve • Measure+it

    • Test+it • Change+it • Poke+it+with+a+s1ck
  32. Ques%ons

  33. class Random(_random.Random): """Random number generator base class used by bound

    module functions. Used to instantiate instances of Random to get generators that don't share state.""" ... # Create one instance, seeded from current time, and export its methods # as module-level functions. The functions share state across all uses #(both in the user's code and in the Python libraries), but that's fine # for most programs and is easier for the casual user than making them # instantiate their own Random() instance. _inst = Random() seed = _inst.seed random = _inst.random randint = _inst.randint choice = _inst.choice ...