visit
The other day, I was looking at some Python code that was made up of a sequence of deeply-nested function calls and a thought immediately got pushed up brain’s stack:
Wouldn’t it be cool if Python had an operator akin to Elixir’s ?
For those of you not familiar with Elixir, the pipe operator |>
can be used to turn code that looks like this:
Nested function calls. Into code that looks like this:
Refreshing! In essence, the pipe operator takes the expression on its left-hand side and moves it into the first argument position of the expression on its right-hand side, assuming the expression on the right is a function call.
The simplest way I could come up with to repurpose the pipe operator was to rewrite functions using a decorator. Python’s built-in ast
module makes this particularly easy.
inspect.getsource
),ast.parse
,The ast
module provides a class called NodeTransformer
that implements the visitor pattern: its visit
method does a depth-first search through an AST and calls any declared methods of the form visit_NODETYPE
on itself for each node in the tree. As the name implies, you can use a node transformer to visit and manipulate the nodes of an AST:
The transformer also kicks in when it sees a function definition so that it may remove the enable_threadop
decorator. This’ll make sense once you take a look at the decorator itself:
The decorator takes a function as an argument, grabs its source code and removes any indentation (this is important! otherwise, decorating class methods results in a SyntaxError
), parses the code and transforms the AST and, finally, it compiles and executes the function definition, returning the resulting function object.
If the transformer hadn’t removed the decorator from the final tree, then we’d have an infinite loop on our hands because enable_threadop
would be called over and over again when the function definition is executed (line 13).
With all that in place, the enable_threadop
decorator may be used to selectively change the behaviour of the pipe operator:
If that’s not a realistic example, I don’t know what is!
First off, inspect.getsource
grabs functions’ source code off of the file system, meaning that the decorator won’t work in the Python interpreter.
Thanks for reading! If you liked the article, give it a clap! You can also find me on my website at , on and .