Several people in this thread have mentioned repeat-until loops, and much of
the discussion here seems to be about how to approximate them in Python. In
readability dreamland:
tries_left = 5 # Must be > 0
repeat:
guess = int(input("Guess? "))
tries -= 1
until guess == secret or tries_left == 0
if guess == secret:
print("You guessed it!")
else:
print("You maxed out.")
A Racket friend of mine likes to point out the many times in our intro course
where we state a problem by saying "do something until X", and then spend time
figuring out how to shoehorn the problem into a while loop.
(Aside: Mark, I find your while-function approach to be thought provoking.)
-Paul Gries
On 2012-04-22, at 4:44 PM, Mark Engelberg wrote:
> John Zelle wrote:
> guess = int(input("Guess? "))
> while(guess != secret): // as long as the user didn't get it, get another
> guess
> print("Nope, try again")
> guess = int(input("Guess? "))
> // Here we know the condition is false
> print("You guessed it")
>
>
> I mostly find John Zelle's version to be more elegant, but I dislike that the
> line:
> guess = int(input("Guess? "))
> occurs in two places.
>
> In general, we should be discouraging writing the same line twice. What if
> you want to change the prompt? What if you want to create more complex error
> checking for the input. Are you going to remember to change it in both
> places?
>
> One reasonable option is to break this out into a separate getGuess()
> function. You'd still end up with two calls to the getGuess() function, but
> at least the logic of getting the guess could easily be changed in one place.
>
> This begs the question, though, as to whether it is possible to rework the
> code to only have one line which gets the guess, without involving continue,
> break, or while(True).
>
> I don't believe there is a way. If Python had tail recursion, one way to
> rewrite this that satisfies all those constraints would be:
>
> def repeatUntilSecretIsGuessed():
> guess = int(input("Guess? "))
> if (guess == secret):
> print("You guessed it")
> else:
> print("Nope, try again")
> repeatUntilSecretIsGuessed()
>
> This would be bad form for Python, though.
>
> One other thought about while/continue/break. I am always thinking about the
> fact that we're training kids for the languages and programming styles that
> will emerge over the next 10+ years. To better understand the future we're
> preparing them for, I spend a lot of time studying emerging languages,
> looking for clues about what styles will best "future-proof" my students.
>
> In the case of while loops, I think it's instructive to look at Scala, a
> language that is currently being hailed as the most plausible successor to
> Java. Scala doesn't have break or continue at all. The idea is that if you
> have a loop that requires a break, it is far clearer to make that loop into a
> separate helper function, and use return instead of break. So for example,
> looking at Kirby's code:
>
> while True: # no ifs ands or buts
> guess = int(input("Guess?: ")
> if guess == secret:
> print("You guessed it!")
> break
> else:
> print("Nope, try again...")
>
> you'd instead write it as:
>
> def repeatUntilSecretIsGuessed():
> while True:
> guess = int(input("Guess?: ")
> if guess == secret:
> print("You guessed it!")
> return
> # It's a bit easier to understand this code because we see it completely
> exits the function here, not just the while loop
> else:
> print("Nope, try again...")
>
> In this example, the distinction seems a little silly, but I would argue that
> the vast majority of while loops are, semantically speaking, "returning a
> value". They do this by setting up some accumulator variable before the
> while loop, and then pounding on the variable, changing it each time through
> the while loop. It can take a bit of analysis to determine which is the
> variable(s) you care about, and what it contains at the time you break out of
> a loop. By breaking the loop into a separate function, and actually
> returning the value you care about with a return statement, the code becomes
> much easier to understand.
>
> So for example, let's say you want to keep looping until you get a guess from
> 1 to 10.
>
> Standard way (using while True and break) would be something like this:
>
> while True:
> guess = int(input("Guess a number from 1 to 10? "))
> if (guess < 1 or guess > 10):
> print ("Try again")
> else:
> break
> # at this point we continue our code, and we know guess contains a number
> from 1 to 10
>
> Better way:
>
> def getNumberFrom1To10():
> while True:
> guess = int(input("Guess a number from 1 to 10? "))
> if (guess < 1 or guess > 10):
> print ("Try again")
> else:
> return guess
> # Now, it's really obvious what is the value that is being "set" by the while
> loop.
>
> In any case, whether you prefer Kirby's while True version or John's version
> which requires asking for a guess both before the loop and inside the loop,
> the main idea here is to get kids thinking each time they have a loop,
> especially a loop that involves break, whether maybe the code would be better
> if they factored out the loop into a separate function.
>
> --Mark
> _______________________________________________
> Edu-sig mailing list
> [email protected]
> http://mail.python.org/mailman/listinfo/edu-sig
_______________________________________________
Edu-sig mailing list
[email protected]
http://mail.python.org/mailman/listinfo/edu-sig