dn <pythonl...@danceswithmice.info> writes: > On 29/08/2021 08.46, Hope Rouselle wrote: >> Here's my solution: >> >> --8<---------------cut here---------------start------------->8--- >> def how_many_times(): >> x, y = 0, 1 >> c = 0 >> while x != y: >> c = c + 1 >> x, y = roll() >> return c, (x, y) > >> >> Why am I unhappy? I'm wish I could confine x, y to the while loop. The >> introduction of ``x, y = 0, 1'' must feel like a trick to a novice. How >> would you write this? > >> r...@zedat.fu-berlin.de (Stefan Ram) writes: >>> """Rolls two dice until both yield the same value. >>> Returns the number of times the two dice were rolled >>> and the final value yielded.""" >>> roll_count = 0 >>> while True: >>> outcome = roll_two_dice() >>> roll_count += 1 >>> if outcome[ 0 ]== outcome[ 1 ]: break >>> return roll_count, outcome[ 0 ] >> >> You totally convinced me. Thanks. > > On the other hand... > whilst you expressed concern about the apparently disconnected 'set up' > necessary before the loop, this solution adds a "True/Forever" and a > "Break" construct, which some may deem not that much better (if at all) > > The idea of abrogating the while-condition but then adding another > (disconnected) condition to break, seems to hold equal potential for > confusion. or the type of dissatisfaction which motivated the original > question!
Pretty well observed! Hats to you. > Looking at that from the inside-out, the loop's contents perform two > functions: the rolling and counting (per Statement of Requirements), but > also a loop-controlling element. Thus the reader's question: "what does > this loop do?" is conflated with "how many times does it do it?". Well put. > Let's go completely off-the-rails, why not use a never-ending range() to > fuel a for-loop 'counter', and within that loop perform the dice-roll(s) > and decide if it is time to 'break'. The range replaces the "True". The > for-loops index or 'counter' will deliver the desired result. > > Neat? No! > Readable? No! > An improvement over the while-True? Definitely not! > Yet, the mechanism is the same AND offers a built-in counter. Hmmm... Yeah. Here's a little context. I came across this by processing a list of exercises. (I'm teaching a course --- you know that by now, I guess.) So the first thing I observed was the equal volume of work dedicated to while loops and for loops --- so I decided to compared which appeared more often in a certain sample of well-written Python code. It turns out the for loop was much more frequent. Students have been reporting too much work in too little time, so I decided to reduce the number of exercises involving while loops. When I began to look at the exercises, to see which ones I'd exclude, I decided to exclude them all --- lol! --- except for one. The one that remained was this one about rolling dice until a satisfying result would appear. (All other ones were totally more naturally written with a for loop.) So if I were to also write this with a for-loop, it'd defeat the purpose of the course's moment. Besides, I don't think a for-loop would improve the readability here. But I thought your protest against the while-True was very well put: while-True is not too readable for a novice. Surely what's readable or more-natural /to someone/ is, well, subjective (yes, by definition). But perhaps we may agree that while rolling dice until a certain success, we want to roll them while something happens or doesn't happen. One of the two. So while-True is a bit of a jump. Therefore, in this case, the easier and more natural option is to say while-x-not-equal-y. But this approach seems to force me into initializing x, y with different values. > Returning to the concern: > > x, y = 0, 1 > c = 0 > > The first line is purely to ensure that the loop executes at least once, > ie the two assigned-values are not 'real'. Hence the disquiet! > > Initiating the counter is unavoidable (@Chris' suggestion notwithstanding). > > However, remember that Python (like decent DBs) has a concept (and an > idiom) of a value to be used when we don't (yet) know what the value > is/should be! Further that Python allows such a value to be used in > comparisons: > >>>> None != None > False >>>> None == None > True > > Leading to: > > c, x, y = 0, None, None > while ... > > > Which solution reverts to the original loop-contents. which seem more > obvious and thus more readable. (YMMV!) > > Simplicity over 'being clever'... I don't see it. You seem to have found what we seem to agree that it would be the more natural way to write the strategy. But I can't see it. It certainly isn't --8<---------------cut here---------------start------------->8--- def how_many_times_1(): c, x, y = 0, None, None while x != y: c = c + 1 x, y = roll() return c, x, y --8<---------------cut here---------------end--------------->8--- nor --8<---------------cut here---------------start------------->8--- def how_many_times_2(): c, x, y = 0, None, None while x == y: c = c + 1 x, y = dados() return c, x, y --8<---------------cut here---------------end--------------->8--- What do you have in mind? I couldn't see it. -- https://mail.python.org/mailman/listinfo/python-list