Exploring*is*Never*Boring
@akaptur
Exploring*is*Never*Boring
Understanding+CPython+without+
reading+the+code
Why$do$this?
!
Contribu)ng
h"ps://docs.python.org/devguide/
"Read&the&code!"
Not$reading$the$code
Strategies
Observa(on
Experimenta+on
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
How$to$observe
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
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
Tools%for%observa,on:%history%&%
changelogs
Tools%for%observa,on:%history%&%changelogs
hg blame Python/ceval.c
hg log -r ### -p
Tools%for%observa,on:%internal%
structure
Tools%for%observa,on:%internal%structure
>>> False is False is False
Tools%for%observa,on:%internal%structure
>>> (False is False) is False
Tools%for%observa,on:%internal%structure
>>> False is False is False
True
Tools%for%observa,on:%internal%structure
>>> False is False is False
True
>>> a < b < c
True
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
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
Strategy(2:(Experimenta1on
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
Tools%for%science:%write%tests
Tools%for%science:%simula0ons
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
Ques%ons
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
...

Exploring slides