Re: Proposal: Complex comprehensions containing statements
I am disliking this proposal at all, more from a gut-feel than anything. But then I just did `import this` and pasted bellow the parts I think this violates. While we all have to keep in mind that the "zen of Python" are more guidelines than absolute standards, they still are _good_ guidelines that have brought the language to where it is. So, these are the zen violations that stroke me on first sight: Simple is better than complex. Flat is better than nested. Sparse is better than dense. Readability counts. In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it. -------- Other than that, I am having trouble to understand how proper indentation of blocks would work under this proposal. Does opening a `[{(` and having any `:` statements inside just imply one more indentation level? Or can the statements inside be validly less indented than the line containing the `= [...` opening bracket? And, just for general, objective feedback, "I am -1 on this". On Fri, 21 Feb 2020 at 11:32, Dominik Vilsmeier <Dominik.Vilsmeier@gmx.de> wrote:
This syntax basically allows to put any code from functions into comprehensions. This enables people to write fewer functions at the cost of more complex comprehensions. But functions are a good idea indeed:
* They have a name and from that name it should be clear what that function does without having to look at the implementation. * Functions can have documentation to provide more information about their behaviour. * Functions have meaningful arguments possibly with type annotations that make it clear what input and output of that operation is. * Functions can be reused. * Functions can be tested.
With that extended comprehension syntax you'll loose all of the above benefits. Since people can put arbitrary complex code into the comprehensions this puts a burden at whoever has to read the code.
As for your first example this is already possible via
[stripped for line in lines if (stripped := line.strip())]
The matrix example is already pretty complex, and the comprehension difficult to read.
Plus for simple comprehensions you have now to ways to write them:
[f(x) for x in stuff] [for x in stuff: f(x)]
I think the first version is much better because you can see immediately what the resulting list contains: f(x) objects. In the second version you have to reach the end of the comprehension to get that information and the `for x in` part is not really interesting. On 2/21/20, 14:49 Alex Hall <alex.mojaki@gmail.com> wrote:
Yes but then it's the same as defining a generator-function.
List comprehensions are already the same as other things, but they're nice anyway. `lambda` is the same as defining a function, but it's nice too. Syntactic sugar is helpful sometimes. I think this:
clean = [ for line in lines: stripped = line.strip() if stripped: yield stripped ]
is easily nicer than this:
def clean_lines(): for line in lines: line = line.strip() if line: yield line
clean = list(clean_lines())
And this:
new_matrix = [ for row in matrix: yield [ for cell in row: try: yield f(cell) except ValueError: yield 0 ] ]
is nicer than any of these:
new_matrix = [] for row in matrix: def new_row(): for cell in row: try: yield f(cell) except ValueError: yield 0
new_matrix.append(list(new_row()))
----
def new_row(row): for cell in row: try: yield f(cell) except ValueError: yield 0
new_matrix = [list(new_row(row)) for row in matrix]
----
def safe_f(cell): try: return f(cell) except ValueError: return 0
new_matrix = [ [ safe_f(cell) for cell in row ] for row in matrix ]
I think it's ambiguous, like in this example: clean = [ for line in lines: stripped = line.strip() if stripped: stripped ] what says that it's the last stripped that should be yielded?
Because it's the only statement that *can* be yielded. The `yield` is implicit when there's exactly one statement you can put it in front of. You can't `yield stripped = line.strip()`. You can technically have `stripped = yield line.strip()` but we ignore those possibilities.
If that function is the whole statement and there is no other expression statement in the comprehension, it will be yielded. I can't tell if there's more to your question. Imagine this one: foo = [ for x in range(5): f(x) if x % 2: x ] what will be the result?
It will be a SyntaxError, because it's ambiguous.
Here's a new idea: `yield` is only optional in inline comprehensions, i.e. where the loop body consists entirely of a single expression. So for example this is allowed:
new_row = [for cell in row: f(cell)]
but this is not:
new_row = [ for cell in row: thing = g(cell) f(thing) ]
Instead the user must write `yield f(thing)` at the end.
This would mean that you only need to add `yield` when the comprehension is already somewhat long so it's less significant, and there's only one very simple special case to learn about. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@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/4QSZ5L... Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@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/D52IFG... Code of Conduct: http://python.org/psf/codeofconduct/
OK, I think the verdict is in and I will not try to debate it.
Does opening a [{( and having any : statements inside just imply one more indentation level? Or can the statements inside be validly less indented than the line containing the = [... opening bracket?
I think this is a fun question. I can't think of any good reason to allow indenting less than the containing statement, but I'm also wondering if there's edge cases I might be missing. If not, then maybe we can indeed just require adding another indentation level. And maybe that means that statements inside expressions wouldn't require a Rube Goldberg machine ;) If anyone is curious, I initially wrote [a much larger proposal with several overlapping subproposals in which `if`, `try`, and `def` could all be used as expressions](https://www.reddit.com/r/Python/comments/f5wm1d/proposal_compound_statement_...). I figured that was hopelessly ambitious and just submitted the part I liked best.
I'll lend a supportive voice here: I like the proposal and would probably make use of this kind of syntax quite a bit, but I think the requirement of yield is definitely a necessity. Too much ambiguity without it. And adding the yield, IMO, doesn't clutter things up too badly. Using one of the code examples, it looks pretty good to me: [ for row in matrix: [ for cell in row: yield f(cell) ] ] Of course, anything that does not contain a yield statement would need to be a syntax error or it could cause problems when refactoring from "regular" looping code, and forgetting to add the yield. --- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler On Fri, Feb 21, 2020 at 3:40 PM Alex Hall <alex.mojaki@gmail.com> wrote:
OK, I think the verdict is in and I will not try to debate it.
Does opening a [{( and having any : statements inside just imply one more indentation level? Or can the statements inside be validly less indented than the line containing the = [... opening bracket?
I think this is a fun question. I can't think of any good reason to allow indenting less than the containing statement, but I'm also wondering if there's edge cases I might be missing. If not, then maybe we can indeed just require adding another indentation level. And maybe that means that statements inside expressions wouldn't require a Rube Goldberg machine ;)
If anyone is curious, I initially wrote [a much larger proposal with several overlapping subproposals in which `if`, `try`, and `def` could all be used as expressions]( https://www.reddit.com/r/Python/comments/f5wm1d/proposal_compound_statement_...). I figured that was hopelessly ambitious and just submitted the part I liked best. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@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/EOUPQC... Code of Conduct: http://python.org/psf/codeofconduct/
Thanks Ricky :) Technically, if yield is always required, it would have to look like this: [ for row in matrix: yield [ for cell in row: yield f(cell) ] ]
participants (4)
-
Alex Hall
-
Dominik Vilsmeier
-
Joao S. O. Bueno
-
Ricky Teachey