Way to repeat other than "for _ in range(x)"

Hi Pythonistas, yet again today I ended up writing: d = [[0] * 5 for _ in range(10)] And wondered, why don't we have a way to repeat other than looping over range() and using a dummy variable? This seems like a rather common thing to do, and while the benefit doesn't seem much, something like this would be much prettier and more pythonic than using underscore variable: d = [[0] * 5 repeat_for 10] And could obviously be used outside of comprehensions too: repeat_for 3: print('Attempting to reconnect...') if reconnect(): break else: print('Unable to reconnect :(') sys.exit(0) I chose to use repeat_for instead of repeat because it's way less likely to be used as a variable name, but obviously other names could be used like loop_for or repeat_times etc. Thoughts?

On 30 March 2017 at 19:18, Markus Meskanen <markusmeskanen@gmail.com> wrote:
Because it's relatively rare to not use the loop variable for anything (even if it's just a debug message), and in the cases where you genuinely don't use it, a standard idiom can be applied (using a single or double underscore as a dummy variable), rather than all future users of the language needing to learn a special case syntax. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Mar 30, 2017 12:53, "Nick Coghlan" <ncoghlan@gmail.com> wrote: Because it's relatively rare to not use the loop variable for anything (even if it's just a debug message), and in the cases where you genuinely don't use it, a standard idiom can be applied (using a single or double underscore as a dummy variable), rather than all future users of the language needing to learn a special case syntax. Cheers, Nick. I

On Thu, Mar 30, 2017 at 12:53 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
I think "relatively rare" is rather subjective, it's surely not everyday stuff but that doesn't mean it's not done often. And instead of learning a special syntax, which is simple and easy to understand when they google "repeat many times python", they now end up learning a special semantic by naming the variable with an underscore. If and when someone asks "how to repeat many times in Python", I'd rather answer "use repeat_for X" instead of "use for _ in range(X)"

If there were to be special syntax for this case, I'd just allow an empty pattern, such as: d = [[0] * 5 for in 10] This is exactly the same as your 'repeat_for' except that it is spelt 'for in', which means there are no new keywords. It would also be allowed in for-loops in the same way as your example. I believe this would even be relatively simple to implement (but don't know). But I'm afraid, I'd be -1 on this, two reasons: 1. Subjective it may be, but my subjective opinion is that this does not come up often enough to warrant this change. 2. When it does come up for those learning the language, they learn a useful idiom of using '_' or '__' for variables that you intend not be used. Thanks, Allan. On 30 March 2017 at 10:59, Markus Meskanen <markusmeskanen@gmail.com> wrote:

On Thu, Mar 30, 2017 at 12:59:57PM +0300, Markus Meskanen wrote:
Let me preface this by saying that, *in principle*, I don't mind the idea of a repeat-without-dummy-variable syntax. I spent a lot of time programming in Apple's Hypertalk back in the 80s and 90s, and it had no fewer than five different loop styles: repeat [forever] repeat until condition repeat while condition repeat with i = start [to|down to] end repeat [for] N [times] where words in [] are optional. That last case is exactly the sort of thing you are talking about: it repeats N times, without creating a loop variable. In Hypertalk's case, this worked really well, and I liked it. So I can say that in principle this is not a bad idea, and it really suits some language styles. But not Python. It works for Hypertalk because it had an already *extremely* verbose and English-like syntax. A typical piece of Hypertalk code might be something like this: add one to total put the value of num after word 4 of item 3 of line 2 of field 1 For Hypertalk's target demographic (non-programmers who happen to be doing a bit of programming) it really is better for the language to provide a close match to their mental concept "repeat five times". The whole language is designed to work like people think, even when that's inefficient. I miss it a lot :-) But Python is a much more general purpose language, and beginners and non-programmers are only a tiny fraction of Python's demographic. Python is only English-like compared to languages like Perl or C which look like line-noise to the uninitiated. So what works for Hypertalk doesn't necessarily work for Python. "repeat 5 times" matches the philosophy and style of Hypertalk, but it clashes with the philosophy and style of Python. Python does not generally go into special-purpose syntax useful only in a specialised situation, preferring instead *general* syntax that can be adapted to a wide-range of situations. Using _ to mean "I don't care about this name" is general purpose. You can use it *anywhere*, not just in loops: # I only care about the side-effects, not the return result _ = call_function() # unpack seven items, but I only care about three of them a, _, b, _, _, _, c = items And it is optional too! If you don't like the name _ you can use anything you like: d = [[0]*5 for whocares in [None]*10] will create your nested lists for you, and probably ever so slightly more efficiently than using range(). So even if there's nothing overtly or especially *bad* about adding specialist syntax to the language, it isn't a great fit to the rest of Python. And of course any change has some cost: - more complexity in the parser and compiler; - more code to implement it; - more features to be tested; - more documentation; - more things for people to learn; - tutorials have more to cover; - people writing a loop have one extra decision to think about; etc. It might not be a *big* cost (it's just one small feature, not an entire Javascript interpreter added to the language!) but it is still a cost. Does the feature's usefulness outweigh its cost? Probably not. It's only a tiny feature, of limited usefulness. At *best* it is a marginal improvement, and it probably isn't even that. I'm not saying it isn't useful. I'm saying it isn't useful *enough*. -- Steve

On 3/30/17, Nick Coghlan <ncoghlan@gmail.com> wrote:
d = [[0]*5]*10 # what about this?
Simplified repeating could be probably useful in interactive mode. Just for curiosity - if PEP-501 will be accepted then how many times could be fnc called in next code? eval(i'{fnc()}, ' *3) PL.

On 31 March 2017 at 00:23, Pavol Lisy <pavol.lisy@gmail.com> wrote:
Once (the same as f-strings), but then it would throw TypeError, as unlike strings and other sequences, InterpolationTemplate wouldn't define a multiplication operator. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On 31 March 2017 at 04:08, Pavol Lisy <pavol.lisy@gmail.com> wrote:
For the same reason dictionaries don't implement it: it doesn't make any sense in the general case. Repeating the *rendered* template might make sense, but that will depend on the specific renderer and the kinds of objects it produces (e.g. an SQL or shell renderer probably wouldn't produce output that supported repetition). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Thu, Mar 30, 2017 at 04:23:05PM +0200, Pavol Lisy wrote:
That doesn't do what you want. It's actually a common "gotcha", since it makes ten repetitions of the same five element list, not ten *copies*. py> d = [[0]*5]*10 py> d[0][0] = 9999 py> print(d) [[9999, 0, 0, 0, 0], [9999, 0, 0, 0, 0], [9999, 0, 0, 0, 0], [9999, 0, 0, 0, 0], [9999, 0, 0, 0, 0], [9999, 0, 0, 0, 0], [9999, 0, 0, 0, 0], [9999, 0, 0, 0, 0], [9999, 0, 0, 0, 0], [9999, 0, 0, 0, 0]] A slightly unfortunate conflict between desires: on the one hand, we definitely don't want * making copies of its arguments; on the other hand, that makes it less useful for initialising multi-dimensional (nested) lists. But then, nested lists ought to be rare. "Flat is better than nested."
Simplified repeating could be probably useful in interactive mode.
I'm sorry, did you just suggest that language features should behave differently in interactive mode than non-interactive mode? If so, that's a TERRIBLE idea. The point of interactive mode is to try out syntax and code and see what it does, before using it in non- interactive scripts. If things behave differently, people will be left confused why the *exact same line of code* works differently in a script and when they try it interactively. It is bad enough that the interactive interpreter includes a handful of features that make it different from non-interactive. I've been caught out repeatedly by the "last evaluated result" variable _ changing when the destructor method __del__ runs. That's another unavoidable case: adding extra, necessary functionality to the interactive interpreter, namely the ability to access the last evaluated result, neccessarily holds onto a reference to that last result. But that's easy enough to reason about, once you remember what's going on. But changing the behaviour of the language itself is just a bad idea. -- Steve

On 3/31/17, Steven D'Aprano <steve@pearwood.info> wrote:
Yes. It is clear that I did mistake here (sorry for that!).
Simplified repeating could be probably useful in interactive mode.
I'm sorry, did you just suggest that language features should behave differently in interactive mode than non-interactive mode?
No. I did not suggest it. In contrary: if it is really useful for interactive python (*) then I suggest to implement it generally! (*) - this is matter of discussion where I don't think this proposal will be accepted... Python is multipurpose language which means that something which is not useful in A may be useful in B. Interactive python could be something like discussing with computer where we don't like to talk too much to say a little.
Sorry, this is not true. Not everybody use interactive python only for testing python constructs. (For example see http://ipython.readthedocs.io/en/stable/interactive/shell.html?highlight=she... ) PL

Your example is really repeating two things: d = [ [0 for _ in range(5)] for _ in range(10) ] But since list() uses * for repetition, you could write it more concisely as: d = [[0] * 5] * 10] I'm not picking on your specific example. I am only pointing out that Python gives you the tools you need to build nice APIs. If repetition is an important part of something you're working on, then consider using itertools.repeat, writing your own domain-specific repeat() method, or even override * like list() does. One of the coolest aspects of Python is how a relatively small set of abstractions can be combined to create lots of useful behaviors. For students, the lack of a "repeat" block might be confusing at first, but once the student understands for loops in general, it's an easy mental jump from "using the loop variable in the body" to "not using the loop variable in the body" to "underscore is the convention for an unused loop variable". In the long run, having one syntax that does many things is simpler than having many syntaxes that each do one little thing. On Thu, Mar 30, 2017 at 5:18 AM, Markus Meskanen <markusmeskanen@gmail.com> wrote:

That's not the same, in the OP example you can assert d[0] is not d[1], while in your code that assertion fails (the list comprehension evaluates the expression each time creating a new list, your code makes 10 references to a single 5 element list) On 30 March 2017 at 14:51, Mark E. Haase <mehaase@gmail.com> wrote:
-- Daniel F. Moisset - UK Country Manager www.machinalis.com Skype: @dmoisset

On 30 March 2017 at 10:51, Mark E. Haase <mehaase@gmail.com> wrote:
I find it weird that not the author, neither the previous repliers noticed that "a repetition other than a for with dummy variable" was already in plain sight, in the very example given. Of course one is also free to write [ [0 for _ in range(5)] for _ in range(10)] if he wishes so.

On Mar 30, 2017 19:04, "Joao S. O. Bueno" <jsbueno@python.org.br> wrote: On 30 March 2017 at 10:51, Mark E. Haase <mehaase@gmail.com> wrote:
I find it weird that not the author, neither the previous repliers noticed that "a repetition other than a for with dummy variable" was already in plain sight, in the very example given. Of course one is also free to write [ [0 for _ in range(5)] for _ in range(10)] if he wishes so. Had you read all the replies, you'd see people (including me, OP) repeating this multiple times: d = [[0] * 5] * 10 Creates a list of ten references *to the same list*. This means that if I mutate any of the sub lists in d, all of the sub lists get mutated. There would only be one sub list, just ten references to it.

On 30 March 2017 at 13:10, Markus Meskanen <markusmeskanen@gmail.com> wrote:
Yes. Nonetheless, it is still repeating. Accepting a new way for doing this would go from 2 ways with 2 semantics to 3 ways with two different semantics. And, all you need is to create a special class to actually dupicate the list on multiplying - not a big deal: In [76]: class D: ...: def __init__(self, value): ...: self.value = value ...: def __rmul__(self, other): ...: if hasattr(other, '__len__') and hasattr(other, '__add__'): ...: result = deepcopy(other) ...: for _ in range(1, self.value): ...: result += deepcopy(other) ...: return result ...: return NotImplemented ...: In [77]: from copy import deepcopy In [78]: a = [[0] * 5] * D(10) In [79]: a[5][2] = "*" In [80]: a Out[80]: [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, '*', 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]

And like I said before, for loop is just another way of doing while loop, yet nobody's complaining. There's nothing wrong with having two different ways of doing the same thing, as long as one of them is never the better way. If we add `repeat`, there's never a reason to use `for _ in range` anymore. What comes to your custom class solution, it's uglier, harder to follow, and way slower than just doing: d = [[0]*5 for _ in range(10)] While the proposed method would be faster, shorter, and cleaner. And like I said many times, the matrix example is just one of many. On Mar 30, 2017 19:54, "Joao S. O. Bueno" <jsbueno@python.org.br> wrote:

On Thu, Mar 30, 2017 at 8:23 PM, Brice PARENT <contact@brice.xyz> wrote:
Your first example:
`for _ in range(x, y, z)`
Makes little sense, since there's still a fixed amount of steps and normal range(x) could just be used instead. As a matter of fact, it can be replaced with either of these, arguably `repeat_for` version being cleaner: for _ in range((y-x+1)//z) repeat_for (y - x + 1) // z And in that one *extremely* unlikely and rare scenario where someone really does need range() with variable start, stop, and step, and doesn't need the returned variable, he can freely still use `for _ in range`. This won't remove it. Your other two examples:
`for _ in one_list` `for _ in any_other_kind_of_iterable`
Aren't related to the syntax I'm proposing, you even quoted this part yourself:
there's never a reason to use `for _ in range` anymore.
But your examples don't use range() to begin with.

That's exactly my point ! What you propose is exaggeratedly specific. It will only work to replace exactly `for _ in range(x)`, nothing more. Every Python developer needs to know about `for i in range(x)`, as it is a really common pattern. It feels really strange to switch to a completely different syntax just for the case we don't care about `i`, a syntax that'll never be used for anything else. And to lose its readability if your `range` requires more that one argument. The Zen of Python tells that way better than I do; - There should be one-- and preferably only one --obvious way to do it. -> As we won't forbid the syntax with range, why add a second obvious way to do it? - Special cases aren't special enough to break the rules. -> The new syntax aims at a very specific special case, don't break the rules for it. -Brice

On 30/03/17 18:06, Markus Meskanen wrote:
That's a C-programmer point of view. In C, it's true; for (init(); cond(); inc()) { ... } is just a convenient form of init(); while (cond()) { ...; inc(); } (ignoring breaks and continues) In Python, the two types of loop are conceptually rather more different. A while loop loops based on a condition; a for loop iterates through an iterable. Doing simple repetition as "for _ in range(x)" is a bit artificial really, but less ugly than doing it with a while loop. Your proposed "repeat" (however it is spelt) is a special case, and a pretty limited one at that. I'm not sure I've needed it, certainly not for a while, and I have to say I don't find array initialisation a compelling use-case. I really don't like the idea of finding it in comprehensions. -- Rhodri James *-* Kynesim Ltd

A for loop in python saves an enormous amount of boilerplate code though (I would post an example, but I'd likely mess up a while loop over an iterator from memory if I posted it here). The `for x in y` construct saves multiple lines an an enormous amount of boilerplate and mental strain in the majority of loops. Your suggestion occasionally saves single digit characters. I'd be curious to know whether implementing this change and then applying the new construct would be a net increase or decrease in the size of the python interpreter and stdlib. Alternatively, writing def repeat_for(func, iters): return func() for _ in range(iters) does what you want without any required syntax changes. On Thu, Mar 30, 2017 at 10:07 AM Markus Meskanen <markusmeskanen@gmail.com> wrote: And like I said before, for loop is just another way of doing while loop, yet nobody's complaining. There's nothing wrong with having two different ways of doing the same thing, as long as one of them is never the better way. If we add `repeat`, there's never a reason to use `for _ in range` anymore. What comes to your custom class solution, it's uglier, harder to follow, and way slower than just doing: d = [[0]*5 for _ in range(10)] While the proposed method would be faster, shorter, and cleaner. And like I said many times, the matrix example is just one of many. On Mar 30, 2017 19:54, "Joao S. O. Bueno" <jsbueno@python.org.br> wrote: On 30 March 2017 at 13:10, Markus Meskanen <markusmeskanen@gmail.com> wrote:
a
Yes. Nonetheless, it is still repeating. Accepting a new way for doing this would go from 2 ways with 2 semantics to 3 ways with two different semantics. And, all you need is to create a special class to actually dupicate the list on multiplying - not a big deal: In [76]: class D: ...: def __init__(self, value): ...: self.value = value ...: def __rmul__(self, other): ...: if hasattr(other, '__len__') and hasattr(other, '__add__'): ...: result = deepcopy(other) ...: for _ in range(1, self.value): ...: result += deepcopy(other) ...: return result ...: return NotImplemented ...: In [77]: from copy import deepcopy In [78]: a = [[0] * 5] * D(10) In [79]: a[5][2] = "*" In [80]: a Out[80]: [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, '*', 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]] _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/

On 31 March 2017 at 03:06, Markus Meskanen <markusmeskanen@gmail.com> wrote:
Well, no, as regularly doing this suggests someone is attempting to write C-in-Python rather than writing Python-in-Python. While C is certainly Python's heritage (especially back in the days before the iterator protocol, when "for i in range(len(container)):" was still a recommended idiom), writing Python code using C idioms isn't even close to being the recommended way of doing things today. So when you say "I use the 'expr for __ in range(count)' pattern a lot", we hear "I don't typically exploit first class functions and the iterator protocol to their full power". And that's fine as far as it goes - 'expr for __ in range(count)' is perfectly acceptable code, and there's nothing wrong with it. However, what it *doesn't* provide is adequate justification for adding an entirely new construct to the language - given other iterator protocol and first class function based tools like enumerate(), itertools.repeat(), zip(), map(), etc, we don't want to add a new non-composable form of iteration purely for the "repeat this operation a known number of times" case. To elaborate on that point, note that any comprehension can always be reformulated as an iteration over a sequence of callables, in this case: init = ([0]*5).copy d = [init() for init in (init,)*10] (This is actually ~20% faster on my machine than the original version with the dummy variable, since it moves the sequence repetition step outside the loop and hence only does it once rather than 10 times) And that can be factored out into a "repeat_call" helper function, with itertools.repeat making it easy to avoid actually creating a tuple: from itertools import repeat def repeat_call(callable, n): for c in repeat(callable, n) yield c() (You can also avoid the itertools dependency by using the dummy variable formulation inside "repeat_call" without the difference being visible to external code) At that point, regardless of the internal implementation details of `repeat_call`, the original example would just look like: d = list(repeat_call(([0]*5).copy, 10)) To say "give me a list containing 10 distinct lists, each containing 5 zeroes". So *if* we were to add anything to the language here, it would be to add `itertools.repeat_call` as a new iteration primitive, since it isn't entirely straightforward to construct that operation out of the existing primitives, with itertools.starmap coming closest: def repeat_call(callable, n): yield from starmap(callable, repeat((), n)) But the explicit for loop being clearest: def repeat_call(callable, n): for __ in range(n): yield callable() Cheers, Nick. P.S. The common problems shared by all of the `repeat_call` formulations in this post are that they don't set __length_hint__ appropriately, and hence lose efficiency when using them to build containers, and also they don't have nice representations they way other itertools objects do. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On 31 March 2017 at 15:12, Nick Coghlan <ncoghlan@gmail.com> wrote:
It occurred to me to check whether or not `more_itertools` already had a suitable operation here, and it does: https://more-itertools.readthedocs.io/en/latest/api.html#more_itertools.repe... This is the `repeatfunc` recipe from the itertools documentation: https://docs.python.org/3/library/itertools.html#itertools-recipes Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Fri, Mar 31, 2017 at 2:49 AM Suresh V. via Python-ideas < python-ideas@python.org> wrote:
If you had read the thread before replying, you would have seen that several people have suggested this, and several others have pointed out why it won't work: because that creates a list of 10 references to the SAME five-element list, meaning that mutating d[0] also affects d[1] through d[9] (since each is the same list). The comprehension is necessary to ensure that each element of d is a distinct list.

On Thu, Mar 30, 2017 at 10:18 AM, Markus Meskanen <markusmeskanen@gmail.com> wrote:
And wondered, why don't we have a way to repeat other than looping over range() and using a dummy variable?
If it's the assignment to a dummy variable that bothers you, the language already has a way around this: Python 3.6.0 (default, Jan 9 2017, 12:18:47) [GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)] on darwin Type "help", "copyright", "credits" or "license" for more information.
Look Ma, no dummy variables! -- Mark

On 30 March 2017 at 19:18, Markus Meskanen <markusmeskanen@gmail.com> wrote:
Because it's relatively rare to not use the loop variable for anything (even if it's just a debug message), and in the cases where you genuinely don't use it, a standard idiom can be applied (using a single or double underscore as a dummy variable), rather than all future users of the language needing to learn a special case syntax. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Mar 30, 2017 12:53, "Nick Coghlan" <ncoghlan@gmail.com> wrote: Because it's relatively rare to not use the loop variable for anything (even if it's just a debug message), and in the cases where you genuinely don't use it, a standard idiom can be applied (using a single or double underscore as a dummy variable), rather than all future users of the language needing to learn a special case syntax. Cheers, Nick. I

On Thu, Mar 30, 2017 at 12:53 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
I think "relatively rare" is rather subjective, it's surely not everyday stuff but that doesn't mean it's not done often. And instead of learning a special syntax, which is simple and easy to understand when they google "repeat many times python", they now end up learning a special semantic by naming the variable with an underscore. If and when someone asks "how to repeat many times in Python", I'd rather answer "use repeat_for X" instead of "use for _ in range(X)"

If there were to be special syntax for this case, I'd just allow an empty pattern, such as: d = [[0] * 5 for in 10] This is exactly the same as your 'repeat_for' except that it is spelt 'for in', which means there are no new keywords. It would also be allowed in for-loops in the same way as your example. I believe this would even be relatively simple to implement (but don't know). But I'm afraid, I'd be -1 on this, two reasons: 1. Subjective it may be, but my subjective opinion is that this does not come up often enough to warrant this change. 2. When it does come up for those learning the language, they learn a useful idiom of using '_' or '__' for variables that you intend not be used. Thanks, Allan. On 30 March 2017 at 10:59, Markus Meskanen <markusmeskanen@gmail.com> wrote:

On Thu, Mar 30, 2017 at 12:59:57PM +0300, Markus Meskanen wrote:
Let me preface this by saying that, *in principle*, I don't mind the idea of a repeat-without-dummy-variable syntax. I spent a lot of time programming in Apple's Hypertalk back in the 80s and 90s, and it had no fewer than five different loop styles: repeat [forever] repeat until condition repeat while condition repeat with i = start [to|down to] end repeat [for] N [times] where words in [] are optional. That last case is exactly the sort of thing you are talking about: it repeats N times, without creating a loop variable. In Hypertalk's case, this worked really well, and I liked it. So I can say that in principle this is not a bad idea, and it really suits some language styles. But not Python. It works for Hypertalk because it had an already *extremely* verbose and English-like syntax. A typical piece of Hypertalk code might be something like this: add one to total put the value of num after word 4 of item 3 of line 2 of field 1 For Hypertalk's target demographic (non-programmers who happen to be doing a bit of programming) it really is better for the language to provide a close match to their mental concept "repeat five times". The whole language is designed to work like people think, even when that's inefficient. I miss it a lot :-) But Python is a much more general purpose language, and beginners and non-programmers are only a tiny fraction of Python's demographic. Python is only English-like compared to languages like Perl or C which look like line-noise to the uninitiated. So what works for Hypertalk doesn't necessarily work for Python. "repeat 5 times" matches the philosophy and style of Hypertalk, but it clashes with the philosophy and style of Python. Python does not generally go into special-purpose syntax useful only in a specialised situation, preferring instead *general* syntax that can be adapted to a wide-range of situations. Using _ to mean "I don't care about this name" is general purpose. You can use it *anywhere*, not just in loops: # I only care about the side-effects, not the return result _ = call_function() # unpack seven items, but I only care about three of them a, _, b, _, _, _, c = items And it is optional too! If you don't like the name _ you can use anything you like: d = [[0]*5 for whocares in [None]*10] will create your nested lists for you, and probably ever so slightly more efficiently than using range(). So even if there's nothing overtly or especially *bad* about adding specialist syntax to the language, it isn't a great fit to the rest of Python. And of course any change has some cost: - more complexity in the parser and compiler; - more code to implement it; - more features to be tested; - more documentation; - more things for people to learn; - tutorials have more to cover; - people writing a loop have one extra decision to think about; etc. It might not be a *big* cost (it's just one small feature, not an entire Javascript interpreter added to the language!) but it is still a cost. Does the feature's usefulness outweigh its cost? Probably not. It's only a tiny feature, of limited usefulness. At *best* it is a marginal improvement, and it probably isn't even that. I'm not saying it isn't useful. I'm saying it isn't useful *enough*. -- Steve

On 3/30/17, Nick Coghlan <ncoghlan@gmail.com> wrote:
d = [[0]*5]*10 # what about this?
Simplified repeating could be probably useful in interactive mode. Just for curiosity - if PEP-501 will be accepted then how many times could be fnc called in next code? eval(i'{fnc()}, ' *3) PL.

On 31 March 2017 at 00:23, Pavol Lisy <pavol.lisy@gmail.com> wrote:
Once (the same as f-strings), but then it would throw TypeError, as unlike strings and other sequences, InterpolationTemplate wouldn't define a multiplication operator. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On 31 March 2017 at 04:08, Pavol Lisy <pavol.lisy@gmail.com> wrote:
For the same reason dictionaries don't implement it: it doesn't make any sense in the general case. Repeating the *rendered* template might make sense, but that will depend on the specific renderer and the kinds of objects it produces (e.g. an SQL or shell renderer probably wouldn't produce output that supported repetition). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Thu, Mar 30, 2017 at 04:23:05PM +0200, Pavol Lisy wrote:
That doesn't do what you want. It's actually a common "gotcha", since it makes ten repetitions of the same five element list, not ten *copies*. py> d = [[0]*5]*10 py> d[0][0] = 9999 py> print(d) [[9999, 0, 0, 0, 0], [9999, 0, 0, 0, 0], [9999, 0, 0, 0, 0], [9999, 0, 0, 0, 0], [9999, 0, 0, 0, 0], [9999, 0, 0, 0, 0], [9999, 0, 0, 0, 0], [9999, 0, 0, 0, 0], [9999, 0, 0, 0, 0], [9999, 0, 0, 0, 0]] A slightly unfortunate conflict between desires: on the one hand, we definitely don't want * making copies of its arguments; on the other hand, that makes it less useful for initialising multi-dimensional (nested) lists. But then, nested lists ought to be rare. "Flat is better than nested."
Simplified repeating could be probably useful in interactive mode.
I'm sorry, did you just suggest that language features should behave differently in interactive mode than non-interactive mode? If so, that's a TERRIBLE idea. The point of interactive mode is to try out syntax and code and see what it does, before using it in non- interactive scripts. If things behave differently, people will be left confused why the *exact same line of code* works differently in a script and when they try it interactively. It is bad enough that the interactive interpreter includes a handful of features that make it different from non-interactive. I've been caught out repeatedly by the "last evaluated result" variable _ changing when the destructor method __del__ runs. That's another unavoidable case: adding extra, necessary functionality to the interactive interpreter, namely the ability to access the last evaluated result, neccessarily holds onto a reference to that last result. But that's easy enough to reason about, once you remember what's going on. But changing the behaviour of the language itself is just a bad idea. -- Steve

On 3/31/17, Steven D'Aprano <steve@pearwood.info> wrote:
Yes. It is clear that I did mistake here (sorry for that!).
Simplified repeating could be probably useful in interactive mode.
I'm sorry, did you just suggest that language features should behave differently in interactive mode than non-interactive mode?
No. I did not suggest it. In contrary: if it is really useful for interactive python (*) then I suggest to implement it generally! (*) - this is matter of discussion where I don't think this proposal will be accepted... Python is multipurpose language which means that something which is not useful in A may be useful in B. Interactive python could be something like discussing with computer where we don't like to talk too much to say a little.
Sorry, this is not true. Not everybody use interactive python only for testing python constructs. (For example see http://ipython.readthedocs.io/en/stable/interactive/shell.html?highlight=she... ) PL

Your example is really repeating two things: d = [ [0 for _ in range(5)] for _ in range(10) ] But since list() uses * for repetition, you could write it more concisely as: d = [[0] * 5] * 10] I'm not picking on your specific example. I am only pointing out that Python gives you the tools you need to build nice APIs. If repetition is an important part of something you're working on, then consider using itertools.repeat, writing your own domain-specific repeat() method, or even override * like list() does. One of the coolest aspects of Python is how a relatively small set of abstractions can be combined to create lots of useful behaviors. For students, the lack of a "repeat" block might be confusing at first, but once the student understands for loops in general, it's an easy mental jump from "using the loop variable in the body" to "not using the loop variable in the body" to "underscore is the convention for an unused loop variable". In the long run, having one syntax that does many things is simpler than having many syntaxes that each do one little thing. On Thu, Mar 30, 2017 at 5:18 AM, Markus Meskanen <markusmeskanen@gmail.com> wrote:

That's not the same, in the OP example you can assert d[0] is not d[1], while in your code that assertion fails (the list comprehension evaluates the expression each time creating a new list, your code makes 10 references to a single 5 element list) On 30 March 2017 at 14:51, Mark E. Haase <mehaase@gmail.com> wrote:
-- Daniel F. Moisset - UK Country Manager www.machinalis.com Skype: @dmoisset

On 30 March 2017 at 10:51, Mark E. Haase <mehaase@gmail.com> wrote:
I find it weird that not the author, neither the previous repliers noticed that "a repetition other than a for with dummy variable" was already in plain sight, in the very example given. Of course one is also free to write [ [0 for _ in range(5)] for _ in range(10)] if he wishes so.

On Mar 30, 2017 19:04, "Joao S. O. Bueno" <jsbueno@python.org.br> wrote: On 30 March 2017 at 10:51, Mark E. Haase <mehaase@gmail.com> wrote:
I find it weird that not the author, neither the previous repliers noticed that "a repetition other than a for with dummy variable" was already in plain sight, in the very example given. Of course one is also free to write [ [0 for _ in range(5)] for _ in range(10)] if he wishes so. Had you read all the replies, you'd see people (including me, OP) repeating this multiple times: d = [[0] * 5] * 10 Creates a list of ten references *to the same list*. This means that if I mutate any of the sub lists in d, all of the sub lists get mutated. There would only be one sub list, just ten references to it.

On 30 March 2017 at 13:10, Markus Meskanen <markusmeskanen@gmail.com> wrote:
Yes. Nonetheless, it is still repeating. Accepting a new way for doing this would go from 2 ways with 2 semantics to 3 ways with two different semantics. And, all you need is to create a special class to actually dupicate the list on multiplying - not a big deal: In [76]: class D: ...: def __init__(self, value): ...: self.value = value ...: def __rmul__(self, other): ...: if hasattr(other, '__len__') and hasattr(other, '__add__'): ...: result = deepcopy(other) ...: for _ in range(1, self.value): ...: result += deepcopy(other) ...: return result ...: return NotImplemented ...: In [77]: from copy import deepcopy In [78]: a = [[0] * 5] * D(10) In [79]: a[5][2] = "*" In [80]: a Out[80]: [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, '*', 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]

And like I said before, for loop is just another way of doing while loop, yet nobody's complaining. There's nothing wrong with having two different ways of doing the same thing, as long as one of them is never the better way. If we add `repeat`, there's never a reason to use `for _ in range` anymore. What comes to your custom class solution, it's uglier, harder to follow, and way slower than just doing: d = [[0]*5 for _ in range(10)] While the proposed method would be faster, shorter, and cleaner. And like I said many times, the matrix example is just one of many. On Mar 30, 2017 19:54, "Joao S. O. Bueno" <jsbueno@python.org.br> wrote:

On Thu, Mar 30, 2017 at 8:23 PM, Brice PARENT <contact@brice.xyz> wrote:
Your first example:
`for _ in range(x, y, z)`
Makes little sense, since there's still a fixed amount of steps and normal range(x) could just be used instead. As a matter of fact, it can be replaced with either of these, arguably `repeat_for` version being cleaner: for _ in range((y-x+1)//z) repeat_for (y - x + 1) // z And in that one *extremely* unlikely and rare scenario where someone really does need range() with variable start, stop, and step, and doesn't need the returned variable, he can freely still use `for _ in range`. This won't remove it. Your other two examples:
`for _ in one_list` `for _ in any_other_kind_of_iterable`
Aren't related to the syntax I'm proposing, you even quoted this part yourself:
there's never a reason to use `for _ in range` anymore.
But your examples don't use range() to begin with.

That's exactly my point ! What you propose is exaggeratedly specific. It will only work to replace exactly `for _ in range(x)`, nothing more. Every Python developer needs to know about `for i in range(x)`, as it is a really common pattern. It feels really strange to switch to a completely different syntax just for the case we don't care about `i`, a syntax that'll never be used for anything else. And to lose its readability if your `range` requires more that one argument. The Zen of Python tells that way better than I do; - There should be one-- and preferably only one --obvious way to do it. -> As we won't forbid the syntax with range, why add a second obvious way to do it? - Special cases aren't special enough to break the rules. -> The new syntax aims at a very specific special case, don't break the rules for it. -Brice

On 30/03/17 18:06, Markus Meskanen wrote:
That's a C-programmer point of view. In C, it's true; for (init(); cond(); inc()) { ... } is just a convenient form of init(); while (cond()) { ...; inc(); } (ignoring breaks and continues) In Python, the two types of loop are conceptually rather more different. A while loop loops based on a condition; a for loop iterates through an iterable. Doing simple repetition as "for _ in range(x)" is a bit artificial really, but less ugly than doing it with a while loop. Your proposed "repeat" (however it is spelt) is a special case, and a pretty limited one at that. I'm not sure I've needed it, certainly not for a while, and I have to say I don't find array initialisation a compelling use-case. I really don't like the idea of finding it in comprehensions. -- Rhodri James *-* Kynesim Ltd

A for loop in python saves an enormous amount of boilerplate code though (I would post an example, but I'd likely mess up a while loop over an iterator from memory if I posted it here). The `for x in y` construct saves multiple lines an an enormous amount of boilerplate and mental strain in the majority of loops. Your suggestion occasionally saves single digit characters. I'd be curious to know whether implementing this change and then applying the new construct would be a net increase or decrease in the size of the python interpreter and stdlib. Alternatively, writing def repeat_for(func, iters): return func() for _ in range(iters) does what you want without any required syntax changes. On Thu, Mar 30, 2017 at 10:07 AM Markus Meskanen <markusmeskanen@gmail.com> wrote: And like I said before, for loop is just another way of doing while loop, yet nobody's complaining. There's nothing wrong with having two different ways of doing the same thing, as long as one of them is never the better way. If we add `repeat`, there's never a reason to use `for _ in range` anymore. What comes to your custom class solution, it's uglier, harder to follow, and way slower than just doing: d = [[0]*5 for _ in range(10)] While the proposed method would be faster, shorter, and cleaner. And like I said many times, the matrix example is just one of many. On Mar 30, 2017 19:54, "Joao S. O. Bueno" <jsbueno@python.org.br> wrote: On 30 March 2017 at 13:10, Markus Meskanen <markusmeskanen@gmail.com> wrote:
a
Yes. Nonetheless, it is still repeating. Accepting a new way for doing this would go from 2 ways with 2 semantics to 3 ways with two different semantics. And, all you need is to create a special class to actually dupicate the list on multiplying - not a big deal: In [76]: class D: ...: def __init__(self, value): ...: self.value = value ...: def __rmul__(self, other): ...: if hasattr(other, '__len__') and hasattr(other, '__add__'): ...: result = deepcopy(other) ...: for _ in range(1, self.value): ...: result += deepcopy(other) ...: return result ...: return NotImplemented ...: In [77]: from copy import deepcopy In [78]: a = [[0] * 5] * D(10) In [79]: a[5][2] = "*" In [80]: a Out[80]: [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, '*', 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]] _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/

On 31 March 2017 at 03:06, Markus Meskanen <markusmeskanen@gmail.com> wrote:
Well, no, as regularly doing this suggests someone is attempting to write C-in-Python rather than writing Python-in-Python. While C is certainly Python's heritage (especially back in the days before the iterator protocol, when "for i in range(len(container)):" was still a recommended idiom), writing Python code using C idioms isn't even close to being the recommended way of doing things today. So when you say "I use the 'expr for __ in range(count)' pattern a lot", we hear "I don't typically exploit first class functions and the iterator protocol to their full power". And that's fine as far as it goes - 'expr for __ in range(count)' is perfectly acceptable code, and there's nothing wrong with it. However, what it *doesn't* provide is adequate justification for adding an entirely new construct to the language - given other iterator protocol and first class function based tools like enumerate(), itertools.repeat(), zip(), map(), etc, we don't want to add a new non-composable form of iteration purely for the "repeat this operation a known number of times" case. To elaborate on that point, note that any comprehension can always be reformulated as an iteration over a sequence of callables, in this case: init = ([0]*5).copy d = [init() for init in (init,)*10] (This is actually ~20% faster on my machine than the original version with the dummy variable, since it moves the sequence repetition step outside the loop and hence only does it once rather than 10 times) And that can be factored out into a "repeat_call" helper function, with itertools.repeat making it easy to avoid actually creating a tuple: from itertools import repeat def repeat_call(callable, n): for c in repeat(callable, n) yield c() (You can also avoid the itertools dependency by using the dummy variable formulation inside "repeat_call" without the difference being visible to external code) At that point, regardless of the internal implementation details of `repeat_call`, the original example would just look like: d = list(repeat_call(([0]*5).copy, 10)) To say "give me a list containing 10 distinct lists, each containing 5 zeroes". So *if* we were to add anything to the language here, it would be to add `itertools.repeat_call` as a new iteration primitive, since it isn't entirely straightforward to construct that operation out of the existing primitives, with itertools.starmap coming closest: def repeat_call(callable, n): yield from starmap(callable, repeat((), n)) But the explicit for loop being clearest: def repeat_call(callable, n): for __ in range(n): yield callable() Cheers, Nick. P.S. The common problems shared by all of the `repeat_call` formulations in this post are that they don't set __length_hint__ appropriately, and hence lose efficiency when using them to build containers, and also they don't have nice representations they way other itertools objects do. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On 31 March 2017 at 15:12, Nick Coghlan <ncoghlan@gmail.com> wrote:
It occurred to me to check whether or not `more_itertools` already had a suitable operation here, and it does: https://more-itertools.readthedocs.io/en/latest/api.html#more_itertools.repe... This is the `repeatfunc` recipe from the itertools documentation: https://docs.python.org/3/library/itertools.html#itertools-recipes Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Fri, Mar 31, 2017 at 2:49 AM Suresh V. via Python-ideas < python-ideas@python.org> wrote:
If you had read the thread before replying, you would have seen that several people have suggested this, and several others have pointed out why it won't work: because that creates a list of 10 references to the SAME five-element list, meaning that mutating d[0] also affects d[1] through d[9] (since each is the same list). The comprehension is necessary to ensure that each element of d is a distinct list.

On Thu, Mar 30, 2017 at 10:18 AM, Markus Meskanen <markusmeskanen@gmail.com> wrote:
And wondered, why don't we have a way to repeat other than looping over range() and using a dummy variable?
If it's the assignment to a dummy variable that bothers you, the language already has a way around this: Python 3.6.0 (default, Jan 9 2017, 12:18:47) [GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)] on darwin Type "help", "copyright", "credits" or "license" for more information.
Look Ma, no dummy variables! -- Mark
participants (16)
-
Allan Clark
-
Brice PARENT
-
Daniel Moisset
-
Joao S. O. Bueno
-
Jonathan Goble
-
Joshua Morton
-
Kyle Lahnakoski
-
Mark Dickinson
-
Mark E. Haase
-
Markus Meskanen
-
Nick Coghlan
-
Pavol Lisy
-
Rhodri James
-
Steven D'Aprano
-
Suresh V.
-
Wolfgang Maier