Adding C-style for loops to Python (2022)
sadh.life
sadh.life
You really do need to be modifying the AST and not just applying a regex to the source code text. This can be a challenge if you want to modify python syntax as you first need to get an AST you can modify, personally I recommend starting with the LARK library and modifying the python syntax grammer it includes.
https://lark-parser.readthedocs.io/en/latest/examples/advanc...
I use similar techniques to transpile openscad code into a python AST in my "pySdfScad" project, while still theoretically getting the benefits of fancy tracebacks and debugging and the like. Probably should have gone with a simple parser instead, but what can you do.
I think they should have stopped at the "cursed way" and not the "truly cursed way", if they really wanted the syntax changes than having your own python parser like the LARK implementation I mention above is a must.
The second method indeed goes very far! I've made some very cool libraries and talks with that alone.
Because you can use coding and then it's somewhat automatic?
But you can do sth similar on AST level, namely installing a meta path finder, i.e. an import module hook which does the AST transformation automatically (https://docs.python.org/3/library/sys.html#sys.meta_path).
Then, there is also the new frame evaluation API (https://peps.python.org/pep-0523/), which allows you to dynamically rewrite bytecode. This has been used by PyTorch 2.0 for torch.compile.
The AST method seems to require you to write "with _for" instead of "for".
The method in part 3 allows you to write "for", which is closer.
So presumably it's better because it gets closer to the objective, although at quite a cost of course.
Repo if anyone is interested: https://github.com/ckw017/blursed
This was inspired by a way less silly usecase, future f-strings, which added f-string support to older versions of Python in a similar way using codecs: https://github.com/asottile-archive/future-fstrings
It's done with AST manipulation as well, but on a larger scale and completer functionalities.
This seems like an interesting avenue for static analysis tools, code generators, (etc.) to explore. Is it a viable approach?
I'd be interested in some analysis on this as a mechanism: performance, maintability, etc. wise.
The "dont do this" argument writes itself; nevertheless, its worth exploring.
Here's an example use cases where the author is trying to create a Python enum from Thrift specs: [2]. The issue here is that the spec code is not necessarily valid Python, but can be fixed easily with some search & replace operations.
[0] https://docs.python.org/3/reference/import.html [1] https://docs.python.org/3/library/modules.html [2] http://wakandan.github.io/2018/06/07/python3-import-hook.htm...
The idea of using (abusing in fact) codecs to pre-process python code before it gets to the actual python interpreter is just fantastic!
I'm starting to think of all the terrible things I'm going to be able to do with this to work around things that have annoyed me for years in python.
[EDIT]: I'm thinking one can probably plug the C preprocessor in python now ... oh the sheer joy :D
Coming from Javascript which has Babel, this is kind of an everyday occurance. Through the magic of source code transforms You can easily add whatever experimental new JS features you want to your project!
for _ in repeat_until_success(timeout=10, backoff=0.1):
if success(...):
breakThere is actually a way to do it with loops.
for attempt in retry(timeout=10, ..)
with attempt:
do_stuff()
Assuming you have a clever implementation of the retry function. IIRC tenacity has one that works like this.Inline loop logic to decide if iteration is successful can be tricky.
I wonder if the codec could use python's lexer (assuming it's exposed) to parse the for loops and nothing else. Then replace the loops with a placeholder, and then replace the placeholder in the AST after a parse. Might be cleaner than source->source transform by the codec, maybe not.
1. I wish more HN posts ended in "for fun" -- so much of what makes being a progammer fun and enjoyable is plumbing the depths of what is possible, not because it's "best practice" or whatever. I think these types of forrays are where true mastery comes from.
2. The less reserved keywords a language has, the better. It makes things like this easier. Years ago I figured out how to implement Goto in Smalltalk "for fun". It was easier because Smalltalk had less reserved keywords.
(defmacro cfor [initialize condition advance #* body]
`(do ~initialize
(while ~condition (do ~@body ~advance))))
(cfor (setv i 0) (< i 10) (+= i 1)
(print i))
This runs on the python vm with hy right now. Took about 2 mins to have it up and running after noticing this post on hn. Couldn't pass it up.My reply to the post was tongue in cheek. The point is that you can add on arbitrary language features to python using hy (any lisp, really). The syntax in question is normally referred to as an s-expression.
cfor(setv(i, 0), i < 10, i += 1) {
print(i)
}Beg your pardon, http://entrian.com/goto/ exists.