1

I'm trying this on a larger piece of code, however to cut it short and simple, this is what I'm trying to do:

  1. To make a TUI based Menu (Like Switch case)
  2. Access functions from it, which return value
  3. Those values being passed into another options of menu

Code:

def menu():  
    ch = int(input('Choice:'))  
    a, b = 1, 1
    # li = ['', '']

    if ch is 1:
        a = 11
        # li[0] = a
        menu()
    elif ch is 2:
        b = 22
        print(a+b)
        # print(li[0]+b)
        menu()
    else:
        print('End')

menu()

When executed:

Choice:1
Choice:2
23
Choice:3
End

Expectation:

Choice:1   # Expecting a = 11
Choice:2   # Expecting 11 + 22
33         # Result to be 33
Choice:3
End

Now, I do understand that is just modifying the local copy of variable. In what way can I get the value to carry forward?

I'm assuming the 11 is value in return from some function written and the second condition is taking the value as parameter for further computation.

I tried this code with a List, however not successful with that. You can check the comments in code.

Not, just with if - else, I went after exec() function to execute, but that just was a bizarre idea.

Any other way is also appreciable.

T3J45
  • 717
  • 3
  • 12
  • 32
  • Direct issues I see: Do not use `is` when you want to test for *value equality*. It is a coincidence that `is 1` works, not by design. Use `== 1`. Do not use recursion to repeatedly ask something, because there is a limited stack and recursive calls *return to their caller*, so you have a stack of calls unwinding. – Martijn Pieters May 22 '18 at 13:13
  • Just tried it, didn't work. Any more Ideas? – T3J45 May 22 '18 at 13:15
  • I didn't say my comment was an answer, just that there were issues to address. – Martijn Pieters May 22 '18 at 13:18

2 Answers2

1

Each call to menu() produces a new, separate local scope, with the variables in that scope independent from other calls to menu(). Changes in one call do not affect the local values in other calls, even recursive ones. So when you call menu(), the new function call starts at the top, and the line a, b = 1, 1 is executed and new, local variables a and b are created, both set to 1.

Don't use recursion. Use a while loop, and break or return to exit the loop when you are done:

def menu():  
    # set the initial values for a and b before starting the loop
    a, b = 1, 1
    while True:
        ch = int(input('Choice:'))  

        if ch == 1:
            a = 11

        elif ch == 2:
            b = 22
            print(a+b)

        else:
            print('End')
            # exit the function, and thus also exit the loop
            return

Demo:

>>> menu()
Choice:1
Choice:2
33
Choice:2
33
Choice:4
End

Recursion is never a good idea for menus anyway; function calls cause the current function state to be pushed on top of a stack, to be retrieved later when the function call returns. That stack has a limited amount of space; too many in-progress function calls and you'll get a runtime error. And you'd be surprised how often users will push a computer menu to those limits.

You could of course pass along the current values of a and b to another function by passing them along as function parameters, and you could return new state back to the caller with return. But it's so much easier to use an endless loop, and that way you don't have to think about having to pass along your program state each time you want to ask the user for the next input.

Note: Do not use is to test for value equality, use ==. is tests for identity, if both expressions reference the same object, not just if two objects have the same value. ch is 1 and ch is 2 only happens to work in CPython because you hit upon an implementation detail of the interpreter.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Why no recursion? "on a larger piece of code" it might be more suitable. – Jonas May 22 '18 at 13:20
  • @Jonas: and recursion is just a decomposition technique, you can *always* replace recursion with an iterative approach. Python doesn't optimise for recursion in any way, so you may want to avoid relying too much on that technique. – Martijn Pieters May 22 '18 at 13:22
  • Tried the code. First I execute with `choice` = 1 and I expect it to change the value of `a` to 11, later when I go for `choice` = 2. It should have returned 33 instead returns 23 again. However, went by your Recommendation and Note. I'll keep that in mind, but I need to get this done for the moment. – T3J45 May 22 '18 at 13:23
  • 1
    @T3J45: ah, that's because I forgot to move the initial `a` and `b` assignments *out* of the loop. Setting them to 1 each time through the loop would indeed not be a good idea. :-) – Martijn Pieters May 22 '18 at 13:27
  • Okay, however I'm trying to get 33, that's what I pointed in Expected section. Just clear me if I'm getting wrong. – T3J45 May 22 '18 at 13:29
  • Well, I'm gonna need to manage memory part now. This was tricky though, I understood that somehow it is rebuilding the memory stack. Just couldn't get how to resolve it. Grateful! – T3J45 May 22 '18 at 13:32
0

When you first call the menu function, you set a and b both to 1. When you make a choice, you call the menu function again, and thus reset a and b both to 1.

You should either remove the initialization of a and b inside the function, initialize them before the call to menu, and pass them as variables to menu. Alternatively, you can remove the calls to menu at each choice and enclose your input and if/else statements within a while loop that will break when ch is equal to some sentinel value.

If you want to do this using recursion, do it like this:

def menu(a, b):
    ch = int(input('Choice:'))
    if ch is 1:
        a = 11
        menu(a,b)
    elif ch is 2:
        b = 22
        print(a+b)
        menu(a,b)
    elif ch is 0:
        print('End')
    else:
        print('Unknown Choice') 

a, b = 1, 1
menu(a, b)

If you want to do it using a while loop, do it like this:

def menu():
        ch = -1  
        a, b = 1, 1        
        while ch != 0:
            ch = int(input('Choice:'))
            if ch is 1:
                a = 11
            elif ch is 2:
                b = 22
                print(a+b)
            elif ch is 0:
                print('End')
            else:
                print('Unknown Choice')
menu()

Hope this helped!

4ur0r4
  • 28
  • 5