Há alguma etiqueta/goto em Python?

Existe um goto ou qualquer equivalente em Python para ser capaz de saltar para uma linha específica de código?

 124
Author: Mu Mind, 2009-01-13

15 answers

Não, o Python não suporta etiquetas e gótico, se é isso que queres. É uma linguagem de programação (altamente estruturada).

 88
Author: unwind, 2009-01-13 12:55:57

Python oferece a você a capacidade de fazer algumas das coisas que você poderia fazer com um goto usando funções de primeira classe. Por exemplo:

void somefunc(int a)
{
    if (a == 1)
        goto label1;
    if (a == 2)
        goto label2;

    label1:
        ...
    label2:
        ...
}

Poderia ser feito em python assim:

def func1():
    ...

def func2():
    ...

funcmap = {1 : func1, 2 : func2}

def somefunc(a):
    funcmap[a]()  #Ugly!  But it works.
Admito que não é a melhor maneira de substituir o goto. Mas sem saber exactamente o que estás a tentar fazer com a gótica, é difícil dar conselhos específicos.

@ascobol:

A melhor opção é colocá-lo numa função ou usar uma excepção. Pela função:

def loopfunc():
    while 1:
        while 1:
            if condition:
                return

À excepção de:

try:
    while 1:
        while 1:
            raise BreakoutException #Not a real exception, invent your own
except BreakoutException:
    pass
Usar exceções para fazer coisas assim pode parecer um pouco estranho se você vem de outra linguagem de programação. Mas eu diria que se você não gosta de usar exceções, Python não é a linguagem para você. :-)
 63
Author: Jason Baker, 2017-05-23 12:18:22

Eu recentemente escrevi um decorador de funções que permite goto em Python, assim do nada:

from goto import with_goto

@with_goto
def range(start, stop):
    i = start
    result = []

    label .begin
    if i == stop:
        goto .end

    result.append(i)
    i += 1
    goto .begin

    label .end
    return result
Não sei porque é que alguém gostaria de fazer uma coisa dessas. Dito isto, não estou a falar muito a sério. Mas eu gostaria de salientar que este tipo de meta-programação é realmente possível em Python, pelo menos em CPython e PyPy, e não só por usar mal a API do depurador como fez outro cara. Mas tens de mexer no bytecode.
 30
Author: Sebastian Noack, 2015-09-20 20:15:04

Para responder ao @ascobol's questão usando a sugestão de @bobince dos comentários:

for i in range(5000):
    for j in range(3000):
        if should_terminate_the_loop:
           break
    else: 
        continue # no break encountered
    break

O travessão para o bloco else está correcto. O código usa obscure else Depois de uma sintaxe de loop Python. Veja Porque é que o python usa 'else' depois de E enquanto os laços?

 15
Author: jfs, 2018-01-23 08:54:12

Encontrei isto na FAQ oficial de desenho e história em python.

Porque não há goto?

Você pode usar exceções para fornecer um "goto estruturado" que até funciona através das chamadas de funções. Muitos sentem que exceções podem convenientemente emular todos os usos razoáveis das construções " go " ou "goto" de C, Fortran, e outras línguas. Por exemplo:

class label(Exception): pass  # declare a label

try:
    ...
    if condition: raise label()  # goto label
    ...
except label:  # where to goto
    pass
... 
Isto não te permite saltar para o meio de um ciclo, mas isso é ... normalmente considerávamos abuso de goto. Usa com moderação.
É muito bom que isto seja mencionado na FAQ oficial, e que seja fornecida uma boa amostra de solução. Eu realmente gosto de python porque sua comunidade está tratando mesmo goto Assim;)
 13
Author: klaas, 2017-06-28 00:21:43

Foi feita uma versão de trabalho: http://entrian.com/goto/.

Nota: foi oferecido como uma piada do Dia Das mentiras. (working though)
# Example 1: Breaking out from a deeply nested loop:
from goto import goto, label

for i in range(1, 10):
    for j in range(1, 20):
        for k in range(1, 30):
            print i, j, k
            if k == 3:
                goto .end
label .end
print "Finished\n"
Escusado será dizer. Sim, é engraçado, mas não o uses.
 9
Author: harmv, 2015-05-21 12:09:07

Os rótulos para break e continue foram propostos em PEP 3136 em 2007, mas foram rejeitados. A Secção motivação da proposta ilustra vários métodos comuns (se deselegantes) para imitar break em Python.

 7
Author: Bill the Lizard, 2012-03-26 22:03:09

É tecnicamente viável adicionar uma declaração tipo 'goto' ao python com algum trabalho. Vamos usar os módulos" dis "e" new", ambos muito úteis para digitalizar e modificar o código Byte python.

A ideia principal por trás da implementação é primeiro marcar um bloco de código como usando "goto" e "label" declarações. Um decorador especial" @goto "será usado com o propósito de marcar funções" goto". Depois digitalizamos esse código para estas duas afirmações e aplicamos o necessário modificações ao código de byte subjacente. Tudo isso acontece no tempo de compilação do código fonte.

import dis, new

def goto(fn):
    """
    A function decorator to add the goto command for a function.

        Specify labels like so:
        label .foo

        Goto labels like so:
        goto .foo

        Note: you can write a goto statement before the correspnding label statement
    """
    labels = {}
    gotos = {}
    globalName = None
    index = 0
    end = len(fn.func_code.co_code)
    i = 0

    # scan through the byte codes to find the labels and gotos
    while i < end:
        op = ord(fn.func_code.co_code[i])
        i += 1
        name = dis.opname[op]

        if op > dis.HAVE_ARGUMENT:
            b1 = ord(fn.func_code.co_code[i])
            b2 = ord(fn.func_code.co_code[i+1])
            num = b2 * 256 + b1

            if name == 'LOAD_GLOBAL':
                globalName = fn.func_code.co_names[num]
                index = i - 1
                i += 2
                continue

            if name == 'LOAD_ATTR':
                if globalName == 'label':
                    labels[fn.func_code.co_names[num]] = index
                elif globalName == 'goto':
                    gotos[fn.func_code.co_names[num]] = index

            name = None
            i += 2

    # no-op the labels
    ilist = list(fn.func_code.co_code)
    for label,index in labels.items():
        ilist[index:index+7] = [chr(dis.opmap['NOP'])]*7

    # change gotos to jumps
    for label,index in gotos.items():
        if label not in labels:
            raise Exception("Missing label: %s"%label)

        target = labels[label] + 7   # skip NOPs
        ilist[index] = chr(dis.opmap['JUMP_ABSOLUTE'])
        ilist[index + 1] = chr(target & 255)
        ilist[index + 2] = chr(target >> 8)

    # create new function from existing function
    c = fn.func_code
    newcode = new.code(c.co_argcount,
                       c.co_nlocals,
                       c.co_stacksize,
                       c.co_flags,
                       ''.join(ilist),
                       c.co_consts,
                       c.co_names,
                       c.co_varnames,
                       c.co_filename,
                       c.co_name,
                       c.co_firstlineno,
                       c.co_lnotab)
    newfn = new.function(newcode,fn.func_globals)
    return newfn


if __name__ == '__main__':

    @goto
    def test1():
        print 'Hello' 

        goto .the_end
        print 'world'

        label .the_end
        print 'the end'

    test1()
Espero que isto responda à pergunta.
 6
Author: Rabih Kodeih, 2015-06-17 00:15:41
Estava à procura de uma coisa semelhante a ...
for a in xrange(1,10):
A_LOOP
    for b in xrange(1,5):
        for c in xrange(1,5):
            for d in xrange(1,5):
                # do some stuff
                if(condition(e)):
                    goto B_LOOP;
Então, a minha abordagem era usar um booleano para ajudar a sair do ninho por laços:
for a in xrange(1,10):
    get_out = False
    for b in xrange(1,5):
        if(get_out): break
        for c in xrange(1,5):
            if(get_out): break
            for d in xrange(1,5):
                # do some stuff
                if(condition(e)):
                    get_out = True
                    break
 3
Author: yaitloutou, 2016-07-07 06:28:25

Pode utilizar excepções definidas pelo Utilizador para emular goto

Exemplo:

class goto1(Exception):
    pass   
class goto2(Exception):
    pass   
class goto3(Exception):
    pass   


def loop():
    print 'start'
    num = input()
    try:
        if num<=0:
            raise goto1
        elif num<=2:
            raise goto2
        elif num<=4:
            raise goto3
        elif num<=6:
            raise goto1
        else:
            print 'end'
            return 0
    except goto1 as e:
        print 'goto1'
        loop()
    except goto2 as e:
        print 'goto2'
        loop()
    except goto3 as e:
        print 'goto3'
        loop()
 2
Author: xavierskip, 2015-03-27 16:07:25

Eu queria a mesma resposta e não queria usar goto. Por isso, usei o seguinte exemplo (do learnpythonthardway)

def sample():
    print "This room is full of gold how much do you want?"
    choice = raw_input("> ")
    how_much = int(choice)
    if "0" in choice or "1" in choice:
        check(how_much)
    else:
        print "Enter a number with 0 or 1"
        sample()

def check(n):
    if n < 150:
        print "You are not greedy, you win"
        exit(0)
    else:
        print "You are nuts!"
        exit(0)
 1
Author: san1512, 2015-07-30 14:28:19
Agora há. goto Acho que isto pode ser útil para o que procuras.
 1
Author: ancho, 2015-09-22 06:33:52
Tenho a minha maneira de fazer godos. Uso scripts python separados.

Se eu quiser repetir:

File1.py

print("test test")
execfile("file2.py")
a = a + 1

File2.py

print(a)
if a == 10:
   execfile("file3.py")
else:
   execfile("file1.py")

File3.py

print(a + " equals 10")

(nota: {[10] } esta técnica só funciona no Python 2.x versions)

 1
Author: Anonaguy, 2018-05-04 17:25:49

Na declaração goto do Python é suportado com goto .<label_name> e label .<label_name>. Para mais informações, por favor, consulte este link .

def func():
    resp = call_something()
    if resp != 0: # Failure case
        goto .failure_handler

    ....
    ....
    resp = ....
    if resp != 0: # Failure case
        goto .failure_handler

    ....
    ....    

    label .failure_handler
    cleanup
    return -1   
Geralmente em todo o planeta, as pessoas recomendam evitar usar a declaração goto. Mas um manuseio de falha em uma função pode ser bem tratado com apenas declaração goto. Mesmo Eu não prefiro o uso de goto a não ser manipulador de falhas.
 0
Author: rashok, 2018-03-01 15:11:47

Para uma partida para a frente, você poderia apenas adicionar:

while True:
  if some condition:
    break
  #... extra code
  break # force code to exit. Needed at end of while loop
#... continues here
No entanto, isto só ajuda para cenários simples (isto é, nidificar estes iria colocá-lo numa confusão)
 0
Author: JGFMK, 2018-06-02 18:53:30