The tracer is a wicked cool Python feature that's often overlooked, because it's so... well, wicked. Here's how it works: you call ``sys.settrace`` on a function, and from now on, that function is invoked *on every single line* with the current stack frame, event and argument. The reason this is so awesome is that you can do pretty much anything if you have access to its stack frame right before it's executed: after all, pretty much everything is an expression of the variables in its local and global scopes, and these are accessible via the ``frame`` object. ![pause](/media/images/pause.png) Let's say you want to troll someone. Here's what you'd do: ```python import sys import webbrowser def tracer(frame, event, arg): if event == 'call': webbrowser.open('https://www.youtube.com/watch?v=dQw4w9WgXcQ') return tracer # A tracer must return itself to keep tracing inner scopes. sys.settrace(tracer) ``` This tracer is going to fire up Rick Roll in the browser whenever a function is called. ![pause](/media/images/pause.png) Seriously, though: let's say you hate ``x``s. Like, literally hate that symbol with the burning rage of a thousand suns, and you do not want it - you *will not have it* - ever considered in your computations. Here's what you'd do: ```python import sys def tracer(frame, event, arg): if 'x' in frame.f_locals: frame.f_locals['x'] = 0 return tracer sys.settrace(tracer) def f(x, y): return x + y assert f(1, 2) == 2 # x is not considered. assert f(3, 4) == 4 # No sir. ``` This tracer is going to zero every ``x``, ever. ![pause](/media/images/pause.png) Seriously, though: there are *even more useful* things you can do with tracers. In fact, that's how debugging, profiling, coverage, and some testing frameworks are implemented. It does incur significant overhead, so it's not recommended for production code... unless you really know what you're doing, which we are. So here's what we're going to do: 1. [Reclaiming Enums](/post/reclaiming-enums) Do you ever miss the way we used to write C-style enums in the good old days? Yeah, neither do I. But what if I told you this is valid Python code: ```python @cenum() class A: a b c = 10 d assert A.a == 0 assert A.b == 1 assert A.c == 10 assert A.d == 11 ``` 2. [Taming Class Attributes](/post/taming-class-attributes) Once upon a time, we needed ordered class attributes. That is, given: ```python class A: x = 1 y = 2 z = 3 ``` We needed ``['x', 'y', 'z']``. "That's easy!" you exclaim; and indeed it is, in Python 3.6. "Well, it was possible before that, too!" you retaliate; and indeed it was, since Python 3.0. But what about *before* that? Can you make this code work in Python 2.7? ```python @ordered() class A: x = 1 y = 2 z = 3 assert A._order == ['x', 'y', 'z'] ``` 3. [Taming Class Scopes](/post/taming-class-scopes) OK, That's a weird one, but it's actually quite handy: say you're using classes for configurations, and want to nest them like so: ```python class config: root = '/app/' class log: path = root + 'log.txt' ``` Turns out that for some obscure reason, scoping doesn't work the way you'd expect it to when it comes to classes: this code ``NameError``s because ``name 'root' is not defined``. Unless... 4. [Tracing Execution](/post/tracing-execution) This example is actually the most useful, but it's also the most boring, so I kept it for last. It lets you trace specific functions in your code, like so: ```python @trace def div(x, y): return x / y div(4, 2) div(1, 0) ``` ```shell $ python div.py calling div(4, 2) calling do_div(4, 2) do_div returned 2 div return 2 calling div(1, 0) calling do_div(1, 0) do_div raised an exception: Traceback (most recent call last): ... ZeroDivisionError: integer division or modulo by zero do_div return None div raised an exception: Traceback (most recent call last): ... ZeroDivisionError: integer division or modulo by zero div returned None ``` So yeah, a lot of nifty stuff. Stay tuned.