On Sun, 26 Jun 2022 at 23:20, Jelle Zijlstra <jelle.zijls...@gmail.com> wrote: > > > > El sáb, 25 jun 2022 a las 13:44, Chris Angelico (<ros...@gmail.com>) escribió: >> >> On Sun, 26 Jun 2022 at 04:41, Brendan Barnwell <brenb...@brenbarn.net> wrote: >> > In contrast, what I would want out of deferred evaluation is >> > precisely >> > the ability to evaluate the deferred expression in the *evaluating* >> > scope (not the definition scope) --- or in a custom provided namespace. >> > Whether this evaluation is implicit or explicit is less important to >> > me than the ability to control the scope in which it occurs. As others >> > mentioned in early posts on this thread, this could complicate things >> > too much to be feasible, but without it I don't really see the point. >> >> A custom-provided namespace can already be partly achieved, but >> working in the evaluating scope is currently impossible and would >> require some major deoptimizations to become possible. >> >> >>> expr = lambda: x + y >> >>> expr.__code__.co_code >> b't\x00t\x01\x17\x00S\x00' >> >>> ns = {"x": 3, "y": 7} >> >>> eval(expr.__code__, ns) >> 10 >> >> This works because the code object doesn't have any locals, so the >> name references are encoded as global lookups, and eval() is happy to >> use arbitrary globals. I say "partly achieved" because this won't work >> if there are any accidental closure variables - you can't isolate the >> lambda function from its original context and force everything to be a >> global: >> >> >>> def f(x): >> ... return lambda: x + y >> ... >> >>> expr = f(42) >> >>> eval(expr.__code__, ns) >> Traceback (most recent call last): >> File "<stdin>", line 1, in <module> >> TypeError: code object passed to eval() may not contain free variables >> >> The mere fact that there's a local variable 'x' means that you can't >> compile the expression 'x + y'. So maybe there'd need to be some weird >> trick with class namespaces, but I'm really not sure what would be >> worth doing. >> > Note that in Python 3.11 exec (but not eval) gains the ability to pass an > explicit closure: > > >>> def f(x): > ... return lambda: print(x + y) > ... > >>> l = f(1) > >>> exec(l.__code__, {"y": 3}, closure=(types.CellType(2),)) > 5 > > This doesn't quite solve the problem being discussed here, but it may help. > > This was added in https://github.com/python/cpython/pull/92204. We didn't add > it to eval() because there was no use case at the time, but it would be easy > to add the same support to eval() too.
Interesting. That would take a bit of extra work (preprocess the dictionary by checking the function object for its variable names, then lifting those out into the separate tuple), but it could be done. ChrisA _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/44JWM546VBY4RHQSQ5THL6N6TBAPZCBZ/ Code of Conduct: http://python.org/psf/codeofconduct/