Macros in Python: quasiquotes, case classes, LINQ and more
github.com
github.com
As an example, instead of hacking the AST via macros:
@case
Point(x, y): pass
one could just do a (this example implies, of course, that there is a CaseClassMeta somewhere attached to CaseClass): class Point(CaseClass):
fields = 'x', 'y'
Not only this is nicer, you retain full control of the MRO on the metaclass level and can adjust its behaviour as needed and when needed.Enums, complex enums and class body nesting examples -- can also be solved via metaclasses quite easily.
Quick lambdas example -- is somewhat close to "whatever" Python library, this is probably the one case which cannot be reproduced as is without AST hacks.
However, the ability to have macros is orthogonal with the feature set of the language. What is interesting is the ability to inspect and modify a Python AST.
Of course, meta-programming is a way to integrate otherwise absent features of a language as-if they were built-in. Python is sufficiently dynamic that most things can be done using existing facilities, like reflection and metaobjects (the @case example, as you mention).
But there is a difference between using those facilites at runtime and producing some code at macro-expansion time (this might be relevant for Cython, for example).
You can, for example, define a domain-specific language that is directly translated as Python, and not interpreted like an API-based representation would. You can even apply custom type checking for that DSL.
Or, you could analyze an existing python source code and produce a translation in another language without having to reimplement a parser (see the Python-to-Javascript example, or Common-Lisp's Parenscript).
Here is my sokal version of class point; just repr overload for complex: https://gist.github.com/jul/9286835
I think the class point is the proof OOP is not able to give a real use case for itself other than reimplementing the wheel poorly.
OOP has proven to be confusing the youngs and lazy. It makes people confused about abstraction and the concrete world (map and territory).
It is pedantic, and inefficient.
EDIT: But the code of this guy is still amazing, even if totally pushing in wrong directions sometimes: memoization is the worst caching strategy possible. On the other hand the PEG parser is brilliant, like most of the code.
with trace:
sum = 0
for i in range(0, 5):
sum = sum + 5
prints sum = 0
for i in range(0, 5):
sum = sum + 5
range(0, 5) -> [0, 1, 2, 3, 4]
sum = sum + 5
sum + 5 -> 5
sum = sum + 5
sum + 5 -> 10
sum = sum + 5
sum + 5 -> 15
sum = sum + 5
sum + 5 -> 20
sum = sum + 5
sum + 5 -> 25
This would save a huge amount of boring typing `print(...)` when debugging,
and since it's only for debugging you don't even need to have MacroPy as a
dependency!Unfortunately python 3.4 support is not quite ready [0], and attempting to install it with `pip3` just fails.
https://pypi.python.org/pypi/q
"import q; q(var1, var2)" forces printing to $TMPDIR/q (usually /tmp/q) very detailed output of what you are tracing and what it is.
The @q decorator does somewhat the same as the "with trace" context manager.
https://github.com/syrusakbary/interpy
previously https://news.ycombinator.com/item?id=9340784
Does JSX-like template for Python count?
https://github.com/dropbox/pyxl
# coding: pyxl
print <html><body>Hello {my_var}!</body></html>
Combined with this, we can make Meteorjs-like applications in Python directly. Even AST transformation of backend DOM operations in Python directly rendered to Javascript to browser.[0]: https://github.com/lihaoyi/macropy#skeletons-in-the-closet