Have you looked at the built-in AST module, ast? 
https://docs.python.org/3/library/ast.html

I don’t see anything preventing you from walking the AST Python itself can give 
you- you’d look for two Set AST nodes if we were to do {{ }}.

There’s also the parser built-in module. You can use it if you first use 
dis.code_info to get the source then re-parse it. It helps with parse trees. 
Parse trees are generated before the AST I think. You’d use the parser module’s 
ST objects with the token module’s constants, for example token.LBRACE or 
token.RBRACE.

Have you looked at the built-in dis module? You can use dis.code_info(obj) to 
get the string of the function. Then you could look for your specified syntax 
with regex and recompile that with the ast module.

Sent from my iPhone

> On Sep 25, 2018, at 1:49 AM, Marko Ristin-Kaufmann <marko.ris...@gmail.com> 
> wrote:
> 
> Hi James,
> Thanks for the feedback!
> 
> I also thought about decompiling the condition to find its AST and figure out 
> what old values are needed. However, this is not so easily done at the moment 
> as all the decompilation libraries I looked at (meta, ucompyle6) are simply 
> struggling to keep up with the development of the python bytecode. In other 
> words, the decompiler needs to be updated with every new version of python 
> which is kind of a loosing race (unless the python devs themselves don't 
> provide this functionality which is not the case as far as I know).
> 
> There is macropy (https://github.com/lihaoyi/macropy) which was suggested on 
> the other thread 
> (https://groups.google.com/forum/#!topic/python-ideas/dmXz_7LH4GI) that I'm 
> currently looking at.
> 
> Cheers,
> Marko
> 
> 
>> On Tue, 25 Sep 2018 at 00:35, James Lu <jam...@gmail.com> wrote:
>> You could disassemble (import dis) the lambda to biew the names of the 
>> lambdas.
>> 
>> @before(lambda self, key, _, length, get: self.length(), self.get(key))
>> 
>> Perhaps you could disassemble the function code and look at all operations 
>> or accesses that are done to “old.” and evaluate those expressions before 
>> the function runs. Then you could “replace” the expression.
>> @post(lambda self, key, old: old.get is None and old.length + 1 ==
>> self.length())
>> 
>> Either the system would grab old.get and old.length or be greedy and grab 
>> old.get is None and old.length + 1. It would then replace the old.get and 
>> old.length with injects that only respond to is None and +1.
>> 
>> Or, a syntax like this 
>> @post(lambda self, key, old: [old.get(old.key)] is None and 
>> [old.self.length() + 1] ==
>> self.length())
>> 
>> Where the stuff inside the brackets is evaluated before the decorated 
>> function runs. It would be useful for networking functions or functions that 
>> do something ephemeral, where data related to the value being accessed 
>> needed for the expression no longer exists after the function. 
>> 
>> This does conflict with list syntax forever, so maybe either force people to 
>> do list((expr,)) or use an alternate syntax like one item set syntax { } or 
>> double set syntax {{ }} or double list syntax [[ ]]. Ditto with having to 
>> avoid the literals for the normal meaning.
>> 
>> You could modify Python to accept any expression for the lambda function and 
>> propose that as a PEP. (Right now it’s hardcoded as a dotted name and 
>> optionally a single argument list surrounded by parentheses.)
>> 
>> I suggest that instead of “@before” it’s “@snapshot” and instead of “old” 
>> it’s “snapshot”.
>> 
>> Python does have unary plus/minus syntax as well as stream operators (<<, 
>> >>) and list slicing syntax and the @ operator and operators & and | if you 
>> want to play with syntax. There’s also the line continuation character for 
>> crazy lambdas.
>> 
>> Personally I prefer
>> @post(lambda self, key, old: {{old.self.get(old.key)}} and 
>> {{old.self.length() + 1}} ==
>> self.length())
>> 
>> because it’s explicit about what it does (evaluate the expressions within {{ 
>> }} before the function runs. I also find it elegant.
>> 
>> Alternatively, inside the {{ }} could be a special scope where locals() is 
>> all the arguments @pre could’ve received as a dictionary. For either option 
>> you can remove the old parameter from the lambda. Example:
>> @post(lambda self, key: {{self.get(key)}} and {{self.length() + 1}} ==
>> self.length())
>> 
>> Perhaps the convention should be to write {{ expr }} (with the spaces in 
>> between).
>> 
>> You’d probably have to use the ast module to inspect it instead of the dis 
>> modul. Then find some way to reconstruct the expressions inside the double 
>> brackets- perhaps by reconstructing the AST and compiling it to a code 
>> object, or perhaps by finding the part of the string the expression is 
>> located. dis can give you the code as a string and you can run a carefully 
>> crafted regex on it.
>> _______________________________________________
>> Python-ideas mailing list
>> Python-ideas@python.org
>> https://mail.python.org/mailman/listinfo/python-ideas
>> Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to