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?
15 answers
Não, o Python não suporta etiquetas e gótico, se é isso que queres. É uma linguagem de programação (altamente estruturada).
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ê. :-)
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.
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?
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;)
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.
É 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.
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
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()
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)
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)
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.
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)