Problem using Switch Case in Python 3

4
print ("ESCOLHA A CERVEJA PELO NUMERO")
print ("1-ANTARTICA R$6.00;2-SKOL R$6.50;3-BRAHMA R$8.20;4-SOL R$8.25;")
cerveja = input ("5-NORTENHA R$16.80;6-PROIBIDA R$4.80;7-DEVASSA R$5.90;8-HEINEKEN R$9.00")

q = float(input("Quantas ???"))

def case_1():
    valor_cerveja = 6 * q
    nome = "Antartida"
def case_2():
    valor_cerveja = 6.5 * q
    nome = "Skol"
def case_3():
    valor_cerveja = 8.2 * q
    nome = "Brahma"
def case_4():
    valor_cerveja = 8.25 * q
    nome = "Sol"
def case_5():
    valor_cerveja = 16.8 * q
    nome = "Nortenha"
def case_6():
    valor_cerveja = 4.8 * q
    nome = "Proibida"
def case_7():
    valor_cerveja = 5.9 * q
    nome = "Devassa"
def case_8():
    valor_cerveja = 9 * q
    nome = "Heineken"
def case_default():
    print "Valor invalido"

print (nome,"custa",valor_cerveja,"Reais, por",q,"cerveja(s)")

It informs that the variable nome has not been defined, but it has been assigned.

    Traceback (most recent call last):
       File "C:/Users/eu/Desktop/algoritmo/cerveja-bar.py", line 34, in <module>
       print (nome,"custa",valor_cerveja,"por",q,"cerveja(s)")
    NameError: name 'nome' is not defined 
>>> 
    
asked by anonymous 26.10.2015 / 05:30

2 answers

11

Python does not have a construct like switch/case - instead, the preferred and simplest way to replace this command, which exists in languages that derived the C syntax, such as Java, Javascript, C ++, C #, among others is to use if of Python, which in addition of else also has the expression elif . The def keyword you use here is how to declare functions and methods in Python - whose main feature is to precisely isolate the internal variables of the environment from which they were invoked.

After showing the simplest (and recommended) form, I'll comment on what's happening in your code:

print ("ESCOLHA A CERVEJA PELO NUMERO")
print ("1-ANTARTICA R$6.00;2-SKOL R$6.50;3-BRAHMA R$8.20;4-SOL R$8.25;")
cerveja = raw_input ("5-NORTENHA R$16.80;6-PROIBIDA R$4.80;7-DEVASSA R$5.90;8-HEINEKEN R$9.00")

q = float(raw_input("Quantas ???"))

if cerveja=="1":
    valor_cerveja = 6 * q
    nome = "Antartida"
elif cerveja=="2":
    valor_cerveja = 6.5 * q
    nome = "Skol"
elif cerveja == "3":
    ...
else:
    nome = None
    print "Valor invalido"
if nome:
    print (nome,"custa",valor_cerveja,"Reais, por",q,"cerveja(s)")

(I put the code for Python 2.x - if using Python 3.x, switch "raw_input" back to input)

Then, in "Python," if is used with "elif" for the equivalent switch / case construct: "elif" is an "else if" contraction - which is used in similar situations when swicth case does not work in other languages - because of the nature of Python that defines which code is inside which block by indentation, it was necessary to create that extra keyword.

One advantage of "elif" over the "case" is that you can put any condition on it - whereas the "case" only allows comparisons with constants. (You also do not need a "break" command.)

Now what happened in your code: you probably looked at some recipe on the internet how to make a switch/case in Python but copied the incomplete recipe - you wrote several functions that would be the body of each case independently above - what you can do - just as you can be done in C, Java. etc ... - but did not put any command for any of these functions to be actually called.

If you want to pass the original recipe link where you looked, I can make a more specific comment - but I suspect that after declaring the various functions of the code body the original recipe defined a dictionary, where the comparison constants of the " case "would be the keys, and the functions would be put as values - for your code it would look something like:

escolhas = {"1": case_1, "2": case_2, "3": case_3, "4": case_4 ...} 
escolhas.get(cerveja, default) (q)

Notice that it gets pretty complicated and the "if / elif" is preferable. The assembly with the dictionary first retrieves an object from the dictionary, based on its switch variable - for example escolhas["1"] - this object is a function, and you can call it - so the call would be escolhas[ cerveja] (q) - the extra pair of parentheses indicates the call to the function itself. In this example, instead of retrieving the dictionary function with the brackets ("[" and "]") I used the "get" method because in this way you can specify a default value if the key does not exist (what you want to do in "default").

Another detail is that while functions in this way can "see" the contents of q as a global variable, it is highly recommended that it be passed as a parameter.

Now, besides its construction, because it does not have this part of the code, it does not call any of the functions, there is a problem in your code with the functions themselves: when using def you define the two variables each in an integer function, and never returns its value - the case_1 function would, for example, be called, would assign the variables, discard those values, and execution would continue, with undefined variables at the point where you called the function. To get around this, you would have to return values of your functions:

def case_1(q):
    valor_cerveja = 6 * q
    nome = "Antartida"
    return valor_cerveja, nome
# ou simplesmente:
def case_2(q):
    return  6.5 * q, "Skol"

escolhas = {...}

nome, valor_cerveja = escolhas.get(cerveja, default)(q)

(See more about returning multiple values of a function here )

And last but not least - for what you want in this program, you do not even need to use "if / elif" (ie different code to run for each value, as in "switch / case" ): the code you want to run is always the same, it just changes the value of beer - this allows you to use a Python dictionary with the data you want - and even more, the data in that dictionary can even be used to print your menu - we use Python's string formatting to include data for each beer on a printed line-

dados = {
   1: ("Antártica", 6),
   2: ("Skol", 8.5),
   3:  ("Brahma", 8.20),
   ...
}
print "Escolha a cerveja: "
for opcao in sorted(dados):
    print ("{} - {} (R$ {:.02f})".format(opcao, dados[opcao][0], dados[opcao][1]))

cerveja = raw_input("Opção: ")
if not cerveja.isdigit() or not int(cerveja) in dados:
     print("Valor inválido")
else:
   qtd = float(raw_input("Quantidade: "))
   nome = dados[opcao][0]
   valor = dados[opcao][1]
   total = qtd * dados[opcao][1]
   print ("{nome} custa {valor} reais por {qtd} cerveja{plural}".format(
       nome=nome, valor=valor, qtd=qtd, plural=("" if qtd == 1 else "s"))
    
29.10.2015 / 20:45
0

I'd rather use context managers ... Here's a tip from Ian Bell.

class Switch:
    def __init__(self, value): 
        self._val = value

    def __enter__(self): 
        return self

    def __exit__(self, type, value, traceback): 
        return False # Allows traceback to occur

    def __call__(self, cond, *mconds): 
        return self._val in (cond,)+mconds

from datetime import datetime

with Switch(datetime.today().weekday()) as case:
    if case(0):
        # Basic usage of switch
        print("I hate mondays so much.")
        # Note there is no break needed here
    elif case(1,2):
        # This switch also supports multiple conditions (in one line)
        print("When is the weekend going to be here?")
    elif case(3,4): 
        print("The weekend is near.")
    else:
        # Default would occur here
        print("Let's go have fun!") # Didn't use case for example purposes
    
01.07.2017 / 15:21