[SOLVED] Function call within Function Fail!
I am not sure why I can't post from a PC web browser, but it sure is irritating... Anyway, can someone explain to a newb why calling "GuessNumber()" inside the except block will iterate thru previous failed attempts, and then returns None ... but "return GuessNumber()" works. It is probably something obvious that hasn't sunk in yet, but I have gotten it to work with just the final "return [variable]" in other code, so it had me beating my head against my desk. Thankfully I had a cut and paste example to reference and I got it to work. Stepping thru the code in a debugger blows my mind too... on the final return it jumps up to the return in the except block (bypassing the print statement) and iterates thru previously failed (non-integer input) before it returns the last correct input. Wha?!!!! 🤯 https://code.sololearn.com/c5pJ3Qeb62KV Hopefully, it is a simple explaination I can digest. 🥴 Finished: https://code.sololearn.com/ctuhz9JNONji
3/7/2020 11:41:15 AMKode Krasher
19 AnswersNew Answer
Code Crasher I'm not sure what you mean when you're talking about monsters and evil twins, so I will leave that part of the conversation alone! 😊 Where you said the except block is called whether the try block is succesfull or not is just not right. I'll try and work through what is happening in the code. Outer function is called (I'll refer to it as GN1 for ease). User inputs to variable (call it gn1). If try block succeeds, gn1 is returned - happy days! If not, GN2 is called. If try in GN2 succeeds, gn2 is returned. Now, if the line in the except block is simply 'GuessNumber()' - i.e. just calling the function and not returning, what happens to the value of gn2? The function call GN2 has performed a successful execution and returned an answer, but gn2 is not assigned to anything. All you have is gn1, which, as there is no other code stopping the execution, gets returned. You've lost the value gn2. If the line is return GuessNumber(), GN2 returns the variable gn2, which is then returned by GN1.
If you run that code in a regular IDE everything executes as expected. in PlayGround there is a special input behavior, as you have to enter all inputs in advance. in PlayGround you can test it by inputting this in 2 separate lines: as 14 "as" will create an exception, then you call again the input which gets the 14. Then the program will output, and terminates without having a problem.
I'm happy, having had such a profound effect on your imagination! 😁
About your question here: You are entering a recursion, when the try block fails. Do you know what this means, and did you intend to do that?
not sure about the evil twin yet... but I am looking out for ways to apply that thought process. I think I am understanding it better now. I tried like 10 fails while debugging, and I can see the GN1, GN2, GN3, etc variables one by one returning in order. so my thought is I need to rethink how I handle validation code? It doesnt matter with single inputs, but I can see where try/except to APIs with this workflow could eat up memory quick. I know I am making this excercise more complicated than it is but I am trying to use functions to get comfortable with them. variable life and disposal problems are definitely becoming more evident as I explore. Russ thanks for hanging in there with this dense brain of mine. You have been great help. Cheers!
Going into recursion is like opening another browser window from a browser window. Do it long enough, and you'll run out of memory. The proper way to do this would be a loop: while True: inp = input() try: inp = int(inp) break except: print('Do you know what a number is?') I prefer this: while True: inp = input() if inp.isdigit(): inp = int(inp) break
HonFu thanks for the code snippet... as always.
√ So here is what my exercise ended up looking like if anyone is interested... https://code.sololearn.com/ctuhz9JNONji It morphed a bit once I started adding the other logic, but this thread helped quite a bit. 👍
Lothar ... The code is running correctly now... I Know... However, my question relates to the use of: return GuessNumber() versus GuessNumber() in the except: block. If I change "return GuessNumber()" to just "GuessNumber()" weird things happen?! I really want to know why? 🤔Hopefully, my explanation above is clear? Thanks for the quick reply though. 🍻 to be clear... copy and paste the code in an IDE and change line 24: return GuessNumber() # Why just "GuessNumber()"" fails? to just: GuessNumber() then step thru the code typing in letters, and watch the exception call the function -- starting over, and then type an integer finally and watch the variables change as it bounces around the return and back to the function call before returning None... to see what I mean.
def innerfunction(): return something def outerfunction(): return innerfunction() outerfunction() Because outerfunction is called, it needs to return something. If you omit the return instruction, innerfunction is called, but its result is lost in outerfunction because nothing is returned. Your question is similar to this, it's just that the innerfunction and outerfunction functions are the same. Your inner GuessNumber() function returns its result to your outer GuessNumber() function. If you don't return it, it gets lost.
No, re-calling GuessNumber() in the except block is not the same as the goto of old. As far as I can remember about BASIC, all variables are global. If you have a variable called n somewhere, you can refer to it anywhere without any problem. This is not the case with Python. Variables can have limited 'scope'. A variable called n that is created within a function is not referable outside of that function. This is also true with recursive functions. The variable guessNumber which is created within your inner-most GuessNumber() function, is not automatically visible to any outer GuessNumber() functions. There can also be a different value of each variable guessNumber in each level of function chain. In order to get the value of inner-most guessNumber variable to the outer-most function, you need to keep returning the value all the way up the line.
Not using return would be the same as simply calling the GuessNumber() function without saving its result to any variable. It's all executed, but its result is lost. Note that an alternative solution is to do guessNumber = GuessNumber() rather than return GuessNumber().
Russ here is a new thought as I hit post... is calling GuessNumber() in the except block creating a copy of the function (a recursion?) of the outer function? (HonFu 's Monsters not dying because the except is creating an evil twin that dies when the twin try: succeeds? Sorry if that is obscure but I read a piece code last night, that i think might apply here?) i am not at my pc, but I think I am going to try and put a return in the try: block before the except: and change line 24 back to see if that has the desired results, and that will answer my question I think. I will kill the monster before it replicates? 😈 (Sorry, it's been a long night.) for reference to my monster obsession: https://code.sololearn.com/c89ejW97QsTN/?ref=app
The interpreter isn't returning to line 24 from line 25. The GN2 function call is at line 24 of GN1. When try in GN2 is successful, it returns gn2 on line 25. The execution of GN1 then resumes from line 24, because that is where the call came from. This is like when you call the outer-most GuesNumber() function, once it's finished running the function, code execution returns to where the call was made from (line 30), it doesn't carry on executing the code that appears after the function definition (back at line 27). The two versions of GuessNumber (GN1 and GN2) are independent of each other. This may be the "evil twins" thing you mentioned.
Code Crasher No worries. Happy to try and help whenever I can.
(Sorry, for the lack of being able to use @Russ... the stupid app won't let me copy and paste, and neither Mac or PC allow me to post anything from Chrome. I don't know what is going on tonight. Thanks just the same @Russ for the reply. It re-enforces some of what I know, but I still have a hard time grasping what I am seeing from my debugger.)... Russ OK, I think I follow... I have been around since Basic on DOS, but programming is not my forte, so learning python has been an experience with wrong assumption from commodore peek and poke days, as well as goto and sub calls... if you follow? My thought was that if I call the GuessNumber() in the except: block, that it was similar to goto... I purposely blow out the variable " guessNumber='' ", thinking that it creates the variable over again with nothing in it to start fresh. But I guess because I never leave the outer function, that it is somehow retaining all the failed attempts? And because I am not returning anything from the except block, that the last guessNumber assignment of '' is being returned from that next iteration of the outer Function? EVEN THOUGH my input->try: should assign the string input, converted to an integer on the outer Function?... Yea... This is what I don't understand.... How is the fact that the except not returning anything on the failed attempts, effecting the last successful input attempt from returning on the outer function?... when the except: call is totally bypassed by the last successful try:? In my mind... the last try: should "return guessNumber" and the except should not even be seen by the interpreter, because the successful assignment of the variable never throws an exception? Am I just thinking about try/except all wrong? Does it evaluate both sections of the block regardless if the try: is True or not?
Russ (ha it works finally (the @ sign)!) you articulate your thoughts well... thank you for that. i do understand scope. i painstakenly beat it into my head with some test code: https://code.sololearn.com/c1bA98jptJ78 I also use guessNumber = GuessNumber() on line 30. my difficulty lies in the GuessNumber() in the except: block being called whether or not the try: is True. Additionally, I don't want anything returned from the except: block. I want that failed try: (non-integer guessNumber variable) to just go to /dev/null or have that register cleared, and just start from the beginning of the function. if the try: succeeds, the "return guessNumber" at the outer level of the function should return ONLY the successful try: and pass it to the "guessNumber = GuessNumber()" call? That is how it works in my brain and how I diagrammed it. why when it hits that last return it is jumping to the function call in the except: is what has me stumped.
HonFu I think I know, yes and no. (Thanks for answering the call!!!) I don't necessarily need to save the state of the variable on fail, so in that sense, no recursion is not desired. It was just how I diagramed it that it ended up that way. I had worked thru a previous password validation code that I used the function inside a function... not because it is the way to do it, because that is what I know right now. Russ made me think of other options, and I have the code working with the guessNumber=GuessNumber() in the except now. The flow of the return on line 25 is what I am trying to understand. Regardless of what call on line 24, after a failed try: and then a 2nd try: succeeds, the return on line 25 goes to 24 before returning. it should not go there on try: success? it should go to the function call in the variable assignment below? why does it go back to the except block first? what is the interpreter doing that it needs to look at that function call again?
Aonle you magaman