[top posting from my phone] Chris Angelico points out the & part of the idea interacts poorly with *args and **kwargs, so I drop that idea.
Re-reading PEP 312, this idea is basically identical, with different spellings. The point remains: do we want to be able to create unevaluated expressions that can be evaluated at a different point? -- Eric. > On Nov 6, 2016, at 8:06 AM, Eric V. Smith <e...@trueblade.com> wrote: > > Creating a new thread, instead of hijacking the PEP 532 discussion. > > From PEP 532: > > > Abstract > > ======== > > > > Inspired by PEP 335, PEP 505, PEP 531, and the related discussions, this PEP > > proposes the addition of a new protocol-driven circuit breaking operator to > > Python that allows the left operand to decide whether or not the expression > > should short circuit and return a result immediately, or else continue > > on with evaluation of the right operand:: > > > > exists(foo) else bar > > missing(foo) else foo.bar() > > Instead of new syntax that only works in this one specific case, I'd prefer a > more general solution. I accept being "more general" probably seals the deal > in killing any proposal! > > I realize the following proposal has at least been hinted at before, but I > couldn't find a specific discussion about it. Since it applies to the > short-circuiting issues addressed by PEP 532 and its predecessors, I thought > I'd bring it up here. It could also be used to solve some of the problems > addressed by the rejected PEP 463 (Exception-catching expressions). See also > PEP 312 (Simple Implicit Lambda). It might also be usable for some of the use > cases presented in PEP 501 (General purpose string interpolation, aka > i-strings). > > I'd rather see the ability to have unevaluated expressions, that can later be > evaluated. I'll use backticks here to mean: "parse, but do not execute the > enclosed code". This produces an object that can later be evaluated with a > new builtin I'll call "evaluate_now". Obviously these are strawmen, and > partly chosen to be ugly and unacceptable names and symbols in the form I'll > discuss here. > > Then you could write a function: > > eval_else(`foo.bar`, `some_func()`) > > whose value is foo.bar, unless foo.bar cannot be evaluated, in which case the > value is some_func(). > > def eval_else(expr, fallback, exlist=(AttributeError,)): > try: > return evaluate_now(expr) > except exlist: > return evaluate_now(fallback) > > Exactly which exceptions you catch is up to you. Of course there's the chance > that someone would pass in something for which the caught exception is too > broad, and it's raised deep inside evaluating the first expression, but > that's no different than catching exceptions now. Except I grant that hiding > the try/except inside a called function increases the risk. > > Like f-strings, the expressions are entirely created at the site they're > specified inside ``. So they'd have access to locals and globals, etc., at > the definition site. > > def x(foo, i): > return eval_else(`foo.bar`, `some_func(i, __name__)`) > > And like the expressions in f-strings, they have to be valid expressions. But > unlike f-strings, they aren't evaluated right when they're encountered. The > fact that they may never be evaluated is one of their features. > > For example the if/else expression: > > if_else(`y`, x is None, `x.a`) > > could be defined as being exactly like: > > y if x is None else x.a > > including only evaluating x.a if x is not None. > > def if_else(a, test, b): > if test: > return evaluate_now(a) > return evaluate_now(b) > > You could do fancier things that require more than 2 expressions. > > Whether `` returns an AST that could later be manipulated, or it's something > else that's opaque is another discussion. Let's assume it's opaque for now. > > You could go further and say that any argument to a function that's specially > marked would get an unevaluated expression. Suppose that you can mark > arguments as & to mean "takes an unevaluated expression". Then you could > write: > > def if_else(&a, test, &b): > if test: > return evaluate_now(a) > return evaluate_now(b) > > And call it as: > if_else(y, x is None, x.a) > > But now you've made it non-obvious at the caller site exactly what's > happening. There are other downsides, such as only being able to create an > unevaluated expression when calling a function. Or maybe that's a good thing! > > In any event, having unevaluated expressions would open up more possibilities > than just the short-circuit evaluation model. And it doesn't involve a new > protocol. > > Eric. > _______________________________________________ > 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/