How to get out of one loop inside another through a function in python?

Asked

Viewed 7,068 times

1

Hi, I’m confused and I’m not getting my code right. What I need is to get out of all the loops through the function ask_continue() after the user responds n input without leaving the program, temporarily, put exit() just to spin at least. here is the code:

print('Olá, seja bem vindo!')
programa = 0
while programa == 0:



def ask_continue():
    ask = str(input("Deseja repetir a operação? (Y/N): "))
    if ask.lower() == 'y':
        program = 0
    elif ask.lower() == 'n':
        programa =+ 1
        exit()


x = 0
while x == 0:
    try:
        a = float(input("Informe a variável 'a': "))
        b = float(input("Informe a variável 'b': "))
        campo_de_saída = a*b-a+b
        print("O campo de saída é {}".format(campo_de_saída))
        ask_continue()
    except:
        print("Valor inválido, tente novamente.")
        x = 0

2 answers

3


This coming out of nested loops really is a generational programming problem.

The command break, as you may know, comes out of a single for or while, and it has to be directly inside that for or while- could not be inside a function called for that purpose.

So if break were the only thing that existed, the only way to solve it would be this:

def funcao_que_resolve_se_sai():
    ...
    return sair_ou_nao

def funcao_principal():
    sair = False
    for laco1 in coisas1:
       for laco2 in coisas2:
           ...
           sair = funcao_que_resolve_se_sai()
           if sair:
                break
       if sair:
           break

That is, you would have to keep the decision to leave within a variable, and have a if with a break in each loop.

In Python, and other high-level languages that have the feature of "exceptions", this is solved with the use of the same.

But "exception is not only when an error occurs?" - not necessarily - an exception may be made deliberately, with the command raise, precisely with the intuition of sending a signal who manages to escape the normal order of execution.

The ideal is to create a custom exception, to differentiate it, even if only semantically, from a real exception, caused by a problem in execution. But to keep the example simple, I will use the RuntimeError even:

def funcao_que_resolve_se_sai():
    ...
    if sair_ou_nao:
        raise RuntimeError()


def funcao_principal():
    try:
       for laco1 in coisas1:
          for laco2 in coisas2:
           ...
           funcao_que_resolve_se_sai()
     except RuntimeError:
         pass

funcao_principal()

Then see how it was- when the "Runtimeerror" exception is caused by the command raise within the call function, the program will jump straight to the next clause except that catch this exception. If the clavicle is after the loops we want to leave, it comes out of all the loops.

Now notice a thing a important: i put the specific function name in the except. In your code, you put except without anything, within their ties - this is a very bad practice, since the except with nothing taken all error types - including errors that you are not expecting, and even more so, including any custom errors that you wanted to use to control the program flow.

So it’s very, very much so always put specific exceptions when using Excecept. In the case of your code, you use except to treat non-numeric values that the user types. The error launched in this case is the ValueError. So your program, inside the bonds, has to capture only the Valueerror!

This technique of custom exceptions is interesting, because no matter how many loops, and how many functions are called within each other (that is - let’s say that the funcao_que_resolve_se_sai call yet another function) - when the exception is launched, the program leaves functions and loops all, up to Except.

This gives a much greater control than calling exit, because after Except, you continue running the program on the next line, normally. (command pass inside Except does nothing, only leaves the block with valid syntax, because it cannot be empty)

This is used in any large Python system - for example, on web systems, frameworks always call your system functions within an appropriate "Try-except" clause - if your code causes any errors, the except for all your code, and generates an HTML page with the appropriate error code - and, the server keeps running normally, expecting other requests.

Finally, the way to customize an exception is also very simple - just create a subclass, which can be empty, of Exception:

class SairDosLacos(Exception):
    pass

def funcao_que_resolve_se_sai():
    ...
    if sair_ou_nao:
        raise SairDosLacos()


def funcao_principal():
    try:
       for laco1 in coisas1:
           for laco2 in coisas2:
              numero_ok = False
              while not numero_ok:
                  try:
                      a  = int(input("digite um número"))
                  except ValueError:
                      print("número inválido, tente de novo - ")
                  else:
                      numero_ok = True
               # codigo usando o número digitado:
               ...
               funcao_que_resolve_se_sai()
     except SairDosLacos:
         pass
funcao_principal()

(note here the use of else to the try/except/else - the block else of command try only executed if no exception has occurred - in that case, if the number is valid)


There’s another form without exceptions, which you can’t use in your case, why don’t you put your main program links within a function - get used to always doing this.

But in addition to an exception with the raise command, another command that exits any number of loops is the return - it terminates the current function immediately, and the control returns to the function that called the current one.

If within the function you will do nothing else after the loops (and you are within a function), it is only by a Return.

Your code would look like this:

print('Olá, seja bem vindo!')
programa = 0
while programa == 0:



def ask_continue():
    ask = str(input("Deseja repetir a operação? (Y/N): "))
    if ask.lower() == 'y':
        program = 0
        return True
    elif ask.lower() == 'n':
        programa =+ 1
        return False


def principal():
    x = 0
    while x == 0:
        try:
            a = float(input("Informe a variável 'a': "))
            b = float(input("Informe a variável 'b': "))
            campo_de_saída = a*b-a+b
            print("O campo de saída é {}".format(campo_de_saída))
            if not ask_continue():
                 return
        except:
            print("Valor inválido, tente novamente.")
            x = 0


Languages that do not have the exception mechanism, such as C, to come out of multiple loops sometimes has the command goto - it can make the execution of the program jump unconditionally to a specific line within the same function.

The programming literature execrates the goto so that its mention causes "fear" in many experienced professionals - because it was the only way to model ties and functions before languages that had functions as we know them today - only because of their extra flexibility, a program could get really hard to follow or understand.

Well used, however, it is the conventional way of getting out of ties - a if in the innermost loop may contain a goto to a point outside all ties. I reiterate that goto does not exist in Python - exists in C, and is the recommended way, for example, to encode error handling if you are creating a C function that will interact, and be called from Python code.

1

I don’t understand what you really want to do, because from what I saw you did a function that just doesn’t come out of the loop... but I will try to solve see below if this is what you want, I took these conditionals that left the infinite loop, because to continue the program just satisfy the question with y, but it is clear that with Exit() the program comes out completely, follows:

class Program():
def __init__(self):
    self.ask_continue()

def ask_continue(self):

    ask = 'y'
    while ask.lower() == 'y':

        a = float(input("Informe a variável 'a': "))
        b = float(input("Informe a variável 'b': "))
        campo_de_saída = a*b-a+b
        print("O campo de saída é {}".format(campo_de_saída))
        ask = str(input("Deseja repetir a operação? (Y/N): "))
        if ask.lower() == 'n':
            programa =+ 1
            exit()







if __name__ == "__main__":
     Program()

Browser other questions tagged

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