Problem using Switch Case in Python 3

Asked

Viewed 40,971 times

6

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 nomewas not defined, but it was 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 
>>> 

2 answers

16


Update 2020: Is being considered for inclusion in Python 3.10 (~October 2021) the functionality of "Pattern matching" with commands match and case. The main purpose allow "destructure" data: that is, from input data that may be in different forms, in JSON, Dictionaries, objects, etc... filter and normalize these entries for direct use in the code below the block. But break, these commands can also be used exactly as the pair switch/case of languages derived from the syntax of C. The justification for inclusion of the commands and summary of the functionality are in PEP 635, with PEP 634 and PEP 636 as auxiliaries. The exact specification, and even the final decision to include these commands, will still be made (after December 2020). The rest of the answer remains valid, and will remain even after these commands are already in the language - TL;DR: use if/elif to replace the switch/case of the C.

original response:

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

After showing the simplest (and recommended) way, I will comment on what is 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 you’re using Python 3.x, change "raw_input" back to input)

So, in Python you use "if" with "Elif" for the equivalent construct of switch/case: "Elif" is a contraction of "Else if" - which is used in similar situations, when swicth case does not serve in other languages - on account of the nature of Python defining which code is within which block by indentation, it was necessary to create that keyword more.

One advantage of "Elif" over "case" is that you can put any condition in it - while "case" only allows comparisons with constants. (There is also no need for a "break command").

Now what happened in your code: you probably looked at some recipe on the internet of 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 can be done - as can be done in C, Java. etc... - but did not put any command so that any of these functions were actually called.

If you want to link to the original recipe you looked at, 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, in which the "case" comparison constants would be the keys, and the functions would be set as values - for your code would look something like:

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

Note that it gets very complicated and the "if/Elif" are preferable. The dictionary mount first retrieves a dictionary object, 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 function of the dictionary with the brackets ("[" and "]") I used the "get" method because this way it is possible to specify a default value if the key does not exist (what you want to do in the "default" ).

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

Now, in addition to its construction, by not having this part of the code, not calling any of the functions, there is a problem in your code with the functions themselves: when using the def you define the two variables each in an isolated function, and never returns the value of them - the function case_1 for example, it would be called, it would assign the variables, it would discard those values and the execution would continue, with the variables undefined at the point where you called the function. To get around this, you would have to return values from 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 from a function here)

And last but not least - for what you want in this program, you don’t even need to use "if/Elif" (that is different code to be executed for each value, as in "switch/case"): the code you want to execute is always the same, only changes the value of the beer - this allows you to use a Python dictionary with the desired data - and even more, the data in that dictionary can be used even to print your menu - we use the string formatting Python 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"))

0

I prefer to use context managers... Follow a suggestion 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

Browser other questions tagged

You are not signed in. Login or sign up in order to post.