On 28 February 2018 at 19:41, Chris Angelico <ros...@gmail.com> wrote: > On Thu, Mar 1, 2018 at 3:30 AM, Paul Moore <p.f.mo...@gmail.com> wrote:
> Here's another equally untested piece of code: > > [(-b + (sqrt(b*b - 4*a*c) as disc)) / (2*a), (-b - disc) / (2*a)] Yeah, that's a good real world example. And IMO it hides the symmetry between the two expressions, so for me it's a good example of a case where there's a readability *disadvantage* with the proposed syntax. > I haven't dug into the implementation consequences of any of this at > global scope. I know what parts of the code I need to look at, but my > days have this annoying habit of having only 24 hours in them. Anyone > got a bugfix for that? :| I can give you daylight saving time and a few leap seconds, but that's more of a workaround than a fix :-) >> Consider >> >> x = 12 >> if (1 as x) == 1: >> def foo(): >> print(x) >> # Actually, you'd probably get a "Name used before definition" >> error here. >> # Would "global x" refer to x=12 or to the statement-local x (1)? >> # Would "nonlocal x" refer to the statement-local x? >> x = 13 >> return x >> print(foo()) > > Yeah, that's going to give UnboundLocalError, because inside foo(), x > has been flagged as local. That's independent of the global scope > changes. > > I'd like to say that "global x" would catch the 12, but until I > actually get around to implementing it, I'm not sure. > >> print(x) >> print(foo()) >> print(x) > > Anything that executes after the 'if' exits should see x as 12. The > temporary variable is completely gone at that point. So simplifying x = 12 if (1 as x) == 1: def foo(): return x print(foo()) print(foo()) prints 1 12 Personally, I can't work out how to think about that in a way that isn't confusing :-( I gather from what you've said elsewhere that your current implementation uses a hidden name-mangled variable. IIRC, list comprehensions used something similar in the original implementation, but it resulted in weird consequences, and ultimately the implementation switched to a "proper" scoped semantics and implementation. I've no particular reason to think your implementation might suffer in the same way, but understanding the semantics in terms of an "assignment to a hidden variable" bothers me. >> The most charitable thing I can say here is that the semantics are >> currently under-specified in the PEP :-) > > Hah. This is why I started out by saying that this ONLY applies inside > a function. Extending this to global scope (and class scope; my guess > is that it'll behave the same as global) is something that I'm only > just now looking into. And yet, "only works within a function" is IMO an unacceptable limitation - so we need to look into the implications here. > So if, in the "in" expression list, you capture something, that thing > will be visible all through the suite. Here's an example: > > for item in (get_items() as items): > print(item) > print(items) > print(items) > > What actually happens is kinda this: > > for item in (get_items() as items_0x142857): > print(item) > print(items_0x142857) > del items_0x142857 > print(items) OK, so that explains why trying to write a closure over a variable introduced via "as" won't work. But I wouldn't want such a renaming to be mandated by the semantics, and I don't know how I'd explain the (implied) behaviour without insisting on a name mangling implementation, so I'm stuck here. >> "What the current proof of concept implementation does" isn't useful >> anyway, but even ignoring that I'd prefer to see what it *does* rather >> than what it *compiles to*. But what needs to be documented is what >> the PEP *proposes* it does. > > The current implementation matches my proposed semantics, as long as > the code in question is all inside a function. Understood. But I'd like the PEP to fully explain more of the intended semantics, *without* referring to the specific implementation. Remember, PyPy, Jython, IronPython, Cython, etc, will all have to implement it too. >> But I can even break expression local names: >> >> x = ((lambda: boom()) as boom) >> x() >> >> It's possible that the "boom" is just my head exploding, not the >> interpreter. But I think I just demonstrated a closure over an >> expression-local name. For added fun, replace "x" with "boom"... > > And this is why I am not trying for expression-local names. If someone > wants to run with a competing proposal for list-comprehension-local > names, sure, but I'm not in favour of that either. Expression-local is > too narrow to be useful AND it still has the problems that > statement-local has. I've no idea how that would work under statement-local names either, though. boom = lambda: boom() boom() is just an infinite recursion. I'm less sure that the as version is. Or the alternative form ((lambda: boom()) as boom)() I know you can tell me what the implementation does - but I can't reason it out from the spec. >>> Thanks for the feedback! Keep it coming! :) >> >> Ask and you shall receive :-) > > If I take a razor and cut myself with it, it's called "self-harm" and > can get me dinged for a psych evaluation. If I take a mailing list and > induce it to send me hundreds of emails and force myself to read them > all... there's probably a padded cell with my name on it somewhere. > > You know, I'd be okay with that actually. Just as long as the cell has wifi. lol. Have fun :-) Paul _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/