¿Hay un goto
o algún equivalente en Python para poder saltar a una línea de código específica?
goto
en Python cuando estaba traduciendo un código Fortran a Python. Se odiaba por eso.
¿Hay un goto
o algún equivalente en Python para poder saltar a una línea de código específica?
goto
en Python cuando estaba traduciendo un código Fortran a Python. Se odiaba por eso.
Respuestas:
Python le ofrece la posibilidad de hacer algunas de las cosas que podría hacer con un goto utilizando funciones de primera clase. Por ejemplo:
void somefunc(int a)
{
if (a == 1)
goto label1;
if (a == 2)
goto label2;
label1:
...
label2:
...
}
Podría hacerse en Python de esta manera:
def func1():
...
def func2():
...
funcmap = {1 : func1, 2 : func2}
def somefunc(a):
funcmap[a]() #Ugly! But it works.
De acuerdo, esa no es la mejor manera de sustituir el goto. Pero sin saber exactamente qué está tratando de hacer con el goto, es difícil dar consejos específicos.
@ ascobol :
Su mejor opción es encerrarlo en una función o usar una excepción. Para la función:
def loopfunc():
while 1:
while 1:
if condition:
return
Por la excepción:
try:
while 1:
while 1:
raise BreakoutException #Not a real exception, invent your own
except BreakoutException:
pass
Usar excepciones para hacer cosas como esta puede ser un poco incómodo si vienes de otro lenguaje de programación. Pero diría que si no te gusta usar excepciones, Python no es el lenguaje para ti. :-)
loopfunc
generalmente requerirá entradas y un poco más de esfuerzo para implementar, pero creo que es la mejor manera en la mayoría de los casos.
Recientemente escribí un decorador de funciones que habilita goto
en Python, así:
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
Sin embargo, no estoy seguro de por qué a uno le gustaría hacer algo así. Dicho esto, no soy demasiado serio al respecto. Pero me gustaría señalar que este tipo de meta programación es realmente posible en Python, al menos en CPython y PyPy, y no solo haciendo un mal uso de la API del depurador como lo hizo ese otro tipo . Sin embargo, debes meterte con el código de bytes.
.begin
y las .end
etiquetas?
Encontré esto en las preguntas frecuentes oficiales sobre diseño e historia de Python .
¿Por qué no hay goto?
Puede usar excepciones para proporcionar un "goto estructurado" que incluso funciona en llamadas a funciones. Muchos sienten que las excepciones pueden emular convenientemente todos los usos razonables de las construcciones "go" o "goto" de C, Fortran y otros lenguajes. Por ejemplo:
class label(Exception): pass # declare a label
try:
...
if condition: raise label() # goto label
...
except label: # where to goto
pass
...
Esto no le permite saltar a la mitad de un bucle, pero de todos modos eso generalmente se considera un abuso de goto. Utilizar con moderación.
Es muy agradable que esto se mencione incluso en las preguntas frecuentes oficiales, y que se proporcione una buena muestra de solución. Realmente me gusta Python porque su comunidad está tratando incluso goto
así;)
goto
es una gran falta de programación para asegurarse, pero las excepciones de abuso de la OMI para emular goto
son solo un poco mejores y aún deben ser mal vistas. Prefiero que los creadores de Python lo incluyan goto
en el lenguaje para las pocas ocasiones en que realmente es útil que no permitirlo porque "es malo, muchachos" y luego recomiendan abusar de las excepciones para obtener la misma funcionalidad (y la misma espaguetización de código).
Para responder a la @ascobol
pregunta usando @bobince
la sugerencia de los comentarios:
for i in range(5000):
for j in range(3000):
if should_terminate_the_loop:
break
else:
continue # no break encountered
break
La sangría para el else
bloque es correcta. El código usa oscuro else
después de una sintaxis de Python en bucle. Consulte ¿Por qué Python usa 'else' después de los bucles for y while?
else
se ejecuta después del ciclo si break
no se ha encontrado. El efecto es que should_terminate_the_loop
termina los bucles internos y externos.
return
sugerido por @Jason Baker es una buena alternativa para salir de los bucles profundamente anidados.
Se ha realizado una versión de trabajo: http://entrian.com/goto/ .
Nota: Se ofreció como una broma de April Fool. (aunque trabajando)
# 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"
No hace falta decir que. Sí, es divertido, pero NO lo use.
Las etiquetas para break
y continue
fueron propuestas en PEP 3136 en 2007, pero fueron rechazadas. La sección de Motivación de la propuesta ilustra varios métodos comunes (aunque poco elegantes) para imitar etiquetados break
en Python.
Es técnicamente factible agregar una declaración 'goto' como python con algo de trabajo. Utilizaremos los módulos "dis" y "nuevos", ambos muy útiles para escanear y modificar el código de bytes de Python.
La idea principal detrás de la implementación es marcar primero un bloque de código como el uso de declaraciones "goto" y "label". Se utilizará un decorador especial "@goto" para marcar las funciones "goto". Luego escaneamos ese código para estas dos declaraciones y aplicamos las modificaciones necesarias al código de bytes subyacente. Todo esto sucede en el tiempo de compilación del código fuente.
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 esto responda la pregunta.
puede usar Excepciones definidas por el usuario para emulargoto
ejemplo:
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()
pip3 install goto-statement
Probado en Python 2.6 a 3.6 y PyPy.
Enlace: goto-declaración
foo.py
from goto import with_goto
@with_goto
def bar():
label .bar_begin
...
goto .bar_begin
Estaba buscando algo similar 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;
Entonces, mi enfoque fue usar un booleano para ayudar a salir de los bucles anidados:
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
Quería la misma respuesta y no quería usarla goto
. Así que usé el siguiente ejemplo (de learnpythonthehardway)
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)
Tengo mi propia forma de hacer gotos. Yo uso scripts de python separados.
Si quiero hacer un bucle:
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: esta técnica solo funciona en las versiones de Python 2.x)
En lugar de un python goto equivalente, uso la instrucción break de la siguiente manera para pruebas rápidas de mi código. Esto supone que tiene una base de código estructurado. La variable de prueba se inicializa al comienzo de su función y simplemente muevo el bloque "If test: break" al final del bloque o bucle anidado if-then que quiero probar, modificando la variable de retorno al final del código para reflejar la variable de bloque o bucle que estoy probando.
def x:
test = True
If y:
# some code
If test:
break
return something
Aunque no hay ningún código equivalente a goto/label
Python, aún podría obtener tal funcionalidad de goto/label
usar bucles.
Tomemos un ejemplo de código que se muestra a continuación donde goto/label
se puede usar en un lenguaje arbitrario que no sea python.
String str1 = 'BACK'
label1:
print('Hello, this program contains goto code\n')
print('Now type BACK if you want the program to go back to the above line of code. Or press the ENTER key if you want the program to continue with further lines of code')
str1 = input()
if str1 == 'BACK'
{
GoTo label1
}
print('Program will continue\nBla bla bla...\nBla bla bla...\nBla bla bla...')
Ahora se puede lograr la misma funcionalidad del ejemplo de código anterior en python usando un while
bucle como se muestra a continuación.
str1 = 'BACK'
while str1 == 'BACK':
print('Hello, this is a python program containing python equivalent code for goto code\n')
print('Now type BACK if you want the program to go back to the above line of code. Or press the ENTER key if you want the program to continue with further lines of code')
str1 = input()
print('Program will continue\nBla bla bla...\nBla bla bla...\nBla bla bla...')
no, hay una forma alternativa de implementar la instrucción goto
class id:
def data1(self):
name=[]
age=[]
n=1
while n>0:
print("1. for enter data")
print("2. update list")
print("3. show data")
print("choose what you want to do ?")
ch=int(input("enter your choice"))
if ch==1:
n=int(input("how many elemet you want to enter="))
for i in range(n):
name.append(input("NAME "))
age.append(int(input("age ")))
elif ch==2:
name.append(input("NAME "))
age.append(int(input("age ")))
elif ch==3:
try:
if name==None:
print("empty list")
else:
print("name \t age")
for i in range(n):
print(name[i]," \t ",age[i])
break
except:
print("list is empty")
print("do want to continue y or n")
ch1=input()
if ch1=="y":
n=n+1
else:
print("name \t age")
for i in range(n):
print(name[i]," \t ",age[i])
n=-1
p1=id()
p1.data1()