... another useful contribution to this thread. ---------- Forwarded message ---------- From: Richard Pattis <pat...@ics.uci.edu> Date: Sat, Apr 21, 2012 at 6:53 PM Subject: I'm not allowed to post To: kirby urner <kirby.ur...@gmail.com>
Feel free to post this for me, which got returned. Probably because I use a mail alias and never tried to post before. Rich I replied to Kirby privately, and he suggested I post to the listserv, so I have. Because UCI is starting to teach Python next year, I might be on the listserv (more than you want) over the summer as I learn Python and how to program in it and teach it: a tall order for a few months. As Charles McCabe (SF Examiner) said, "Any clod can have the facts; having opinions is an art." - rep Kirby, I'm a long time Java teacher (heck, I started teaching Fortran in 1976) who will soon be teaching Python. We (here at UC Irvine) are switching to a 3 quarter introduction to programming sequence all in Python (and then on to Java and C++ for upper division courses, although Python could leak upwards). I've been subscribing to edu-sig Python for a while and appreciate your efforts (and have learned from them). I'm a big fan in Java of teaching beginners only for(;;) -I call it for-ever- and if/break termination (although some colleagues accuse me of teaching machine language in Java). I like forever if/break for a few reasons, among them are I teach ifs right before looping, so students get a chance to immediately use ifs; I think it is easier to state the condition in which to break instead of the condition in which to continue (although we discuss how to compute one from the other by DeMorgan's laws later); there is only one looping form, so students aren't faced with the up-front decision of what kind of loop to use; and finally, they can fully write the loop and its body and then worry about termination later (unlike a while loop, where syntactically the first thing you must write is the continuation test -although some computer scientists would consider this a feature, not a bug). So my students don't have to think of which Java loop to use: while or do/while. They code everything (early in class) using forever if/break, although later I illustrate the semantics of Java's other looping forms, using forever if/break (which they are familiar with), tell them if the pattern fits, do the transformation to simplify their code, and if you do this enough, later in the course you will write the "right" pattern first, without thinking about the transformation. I'm not a big fan of continue here. I conceptualize this as an N=1/2 loop (sentinel loops are also of this form) and am happy with forever if/break; The question I'd have for a while loop, is where does guess come from the first time the test is evaluated; if the answer is some initialization that is not equal to secret, I'd say yuck: guess should store the user's guesses only, not some crazy value to make things work the first time the loop is entered. Another reason I don't like continue is that it isn't local; you have to "go around the loop again to exit".; and will you exit the next time around, it doesn't jump out at me (same, but a little less so, for your exit = True code in the later example; more soon). With break, you recognize termination and perform the action immediately (like return). Also, you have to have the condition stated twice in your final code, in two opposite forms (guess != secret) and also (guess == secret); confusing and double yuck. Now in Java you could write this as a do/while,but you still have the "repeat the test in two opposite forms" problem. In your summary > In short: never use break to exit a while loop > unless your condition is while True. I agree with this, and argue this should be your loop form always for beginners. I also require (for most of the quarter) at most one break per loop. > However, as soon as I make that rule I can > think of good reasons to break it. Yes, I believe you should break that rule, not continue to use it In the next code you set exit = True then continue so the next iteration terminates the loop, which I think is also bad because of non-locality. You are terminating indirectly all over the loop. I tell my students since loop termination is what the loop is all about, it should be obvious where you are terminating and why. I start by making them put their break statements in comment sandwiches, so they stand out: ////// break; ////// OK, so how would I write your loop to match its semantics, but be as simple as possible? Before showing my code, I dislike the fact that your code is impolite: it always says "try again" on a wrong guess, but then sometimes doesn't let the user try again. So I'll fix this "feature". In fact, your code infinite loops when allowed = 1 (because tries, which is initialized at 1, is incremented before it is tested == allowed); in other cases it is impolite and gives the user one fewer try than they should get; so I'll fix those bugs (you could fix them by setting tries to 0, which I think is right, because the user hasn't tried yet; I'd increment tries right before or after the user enters a new guess: more locality). Moral, never post code to the internet: the bas**rds will tear you apart). Here is my Java in Python code. I'm assuming that the user always gets at least one guess. allowed = 5 tries = 0 while true: guess = int(input("Guess?: ") tries += 1 if guess == secret: print("You guessed it!") break; # terminate loop if tries == allowed: print("You've maxed out") break; # terminate loop print("Nope, try again...") one fewer variable (no exit; Sartre had good programming intuition) two fewer (18%) statements in the loop body. Now, we can still do some things to reduce the size (but possibly increase the complexity of understanding this code, and requiring knowledge of an "advance" python feature) while true: guess = int(input("Guess?: ") tries += 1 if guess == secret or tries == allowed break # terminate loop print("Nope, try again...") print("You guessed it" if guess == secret else "You've maxed out") Note the last statement cannot be if tries != allowed, because both might be true, but the secret test does what you want. What I like about this solution is it localizes the termination test (one break) and the final disposition of the game (one "you won/lost" statement). What I dislike about it (I'm no Pygmalion) is the uncoupling between the termination and printing, and it has "redundant " tests (now three, instead of two: one of my big complaints in the code you started this discussion with). I admit, I didn't follow any "simple to state" rules when writing this code. My rule of thumb is not to minimize the number of loop exits but to minimize the complexity, and I'm not totally sure what that means. Feel free to rip me for any mistakes I've made, but now I'm off to think about "private" variables in Python classes. Rich Pattis [ trimmed off copy of Kirby's essay -- Kirby ] _______________________________________________ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig