C'è un goto
o qualche equivalente in Python per essere in grado di passare a una specifica riga di codice?
goto
in Python mentre traduceva un codice Fortran in Python. Si odiava per questo.
C'è un goto
o qualche equivalente in Python per essere in grado di passare a una specifica riga di codice?
goto
in Python mentre traduceva un codice Fortran in Python. Si odiava per questo.
Risposte:
No, Python non supporta etichette e goto, se è quello che stai cercando. È un linguaggio di programmazione (altamente) strutturato.
Python ti offre la possibilità di fare alcune delle cose che potresti fare con un goto usando funzioni di prima classe. Per esempio:
void somefunc(int a)
{
if (a == 1)
goto label1;
if (a == 2)
goto label2;
label1:
...
label2:
...
}
Potrebbe essere fatto in Python in questo modo:
def func1():
...
def func2():
...
funcmap = {1 : func1, 2 : func2}
def somefunc(a):
funcmap[a]() #Ugly! But it works.
Certo, non è il modo migliore per sostituire Goto. Ma senza sapere esattamente cosa stai cercando di fare con il goto, è difficile dare consigli specifici.
@ ascobol :
La soluzione migliore è racchiuderla in una funzione o utilizzare un'eccezione. Per la funzione:
def loopfunc():
while 1:
while 1:
if condition:
return
Per l'eccezione:
try:
while 1:
while 1:
raise BreakoutException #Not a real exception, invent your own
except BreakoutException:
pass
Usare le eccezioni per fare cose del genere può sembrare un po 'imbarazzante se vieni da un altro linguaggio di programmazione. Ma direi che se non ti piace usare le eccezioni, Python non è la lingua che fa per te. :-)
loopfunc
generalmente richiederà input e qualche sforzo in più da implementare, ma è il modo migliore nella maggior parte dei casi penso.
Di recente ho scritto un decoratore di funzioni che abilita goto
in Python, proprio così:
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
Non sono sicuro del motivo per cui uno vorrebbe fare qualcosa del genere però. Detto questo, non sono troppo serio. Ma vorrei sottolineare che questo tipo di meta-programmazione è effettivamente possibile in Python, almeno in CPython e PyPy, e non solo abusando dell'API di debugger come faceva l' altro ragazzo . Devi pasticciare con il bytecode però.
.begin
ed .end
etichette?
L'ho trovato nelle FAQ ufficiali su Design e Storia di Python .
Perché non c'è goto?
È possibile utilizzare le eccezioni per fornire un "goto strutturato" che funzioni anche attraverso le chiamate di funzione. Molti ritengono che le eccezioni possano facilmente emulare tutti gli usi ragionevoli dei costrutti "go" o "goto" di C, Fortran e altre lingue. Per esempio:
class label(Exception): pass # declare a label
try:
...
if condition: raise label() # goto label
...
except label: # where to goto
pass
...
Questo non ti consente di saltare nel mezzo di un loop, ma di solito è considerato un abuso di goto. Usa con parsimonia.
È molto bello che questo sia anche menzionato nelle FAQ ufficiali e che sia fornito un esempio di soluzione piacevole. Mi piace molto Python perché la sua community sta trattando anche in goto
questo modo;)
goto
è un importante passo in avanti per la programmazione, ma le eccezioni dell'OMO che abusano di emulare goto
è solo leggermente migliore e dovrebbe essere ancora fortemente disapprovato. Preferirei che i creatori di Python includessero goto
nel linguaggio per le poche occasioni in cui in realtà è utile che non consentirlo perché "è un male, ragazzi" e quindi raccomandare di abusare delle eccezioni per ottenere la stessa funzionalità (e lo stesso spaghettificazione del codice).
Per rispondere alla @ascobol
domanda usando @bobince
il suggerimento dei commenti:
for i in range(5000):
for j in range(3000):
if should_terminate_the_loop:
break
else:
continue # no break encountered
break
Il trattino per il else
blocco è corretto. Il codice usa oscuro else
dopo una sintassi Python in loop. Vedi Perché python usa 'else' dopo e per i cicli while?
else
viene eseguito dopo il ciclo se break
non è stato riscontrato. L'effetto è che should_terminate_the_loop
termina entrambi i cicli interni ed esterni.
return
suggerito da @Jason Baker è una buona alternativa per uscire da anelli profondamente annidati.
È stata realizzata una versione funzionante: http://entrian.com/goto/ .
Nota: è stato offerto come uno scherzo del pesce d'aprile. (funzionando però)
# 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"
Inutile dire che. Sì, è divertente, ma NON usarlo.
Le etichette per break
e continue
sono state proposte in PEP 3136 nel 2007, ma è stata respinta. La sezione Motivazione della proposta illustra diversi metodi comuni (se non eleganti) per l'imitazione etichettati break
in Python.
È tecnicamente possibile aggiungere un'istruzione simile a "goto" su Python con qualche lavoro. Useremo i moduli "dis" e "new", entrambi molto utili per la scansione e la modifica del codice byte python.
L'idea principale dietro l'implementazione è di contrassegnare innanzitutto un blocco di codice come usando le istruzioni "goto" e "label". Uno speciale decoratore "@goto" verrà utilizzato per contrassegnare le funzioni "goto". Successivamente scansioniamo quel codice per queste due istruzioni e applichiamo le modifiche necessarie al codice byte sottostante. Tutto ciò accade al momento della compilazione del codice sorgente.
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()
Spero che questo risponda alla domanda.
è possibile utilizzare le eccezioni definite dall'utente per emularegoto
esempio:
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
Testato su Python da 2.6 a 3.6 e PyPy.
Link: goto-statement
foo.py
from goto import with_goto
@with_goto
def bar():
label .bar_begin
...
goto .bar_begin
Stavo cercando qualcosa di simile 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;
Quindi il mio approccio è stato quello di usare un booleano per evadere dai loop nidificati:
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
Volevo la stessa risposta e non volevo usare goto
. Quindi ho usato il seguente esempio (da 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)
Ho il mio modo di fare goto. Uso script Python separati.
Se voglio fare un ciclo:
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: questa tecnica funziona solo su versioni Python 2.x)
Al posto di un equivalente di Python Goto, utilizzo la seguente dichiarazione di interruzione nel modo seguente per test rapidi del mio codice. Ciò presuppone che tu abbia una base di codice strutturata. La variabile test viene inizializzata all'inizio della tua funzione e sposto semplicemente il blocco "If test: break" alla fine del blocco if-then nidificato che voglio testare, modificando la variabile return alla fine del codice per riflettere la variabile di blocco o loop che sto testando.
def x:
test = True
If y:
# some code
If test:
break
return something
Sebbene non ci sia un codice equivalente a goto/label
in Python, potresti comunque ottenere tale funzionalità goto/label
usando i loop.
Consente di prendere un esempio di codice mostrato di seguito in cui goto/label
può essere utilizzato in un linguaggio arbitrario diverso da 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...')
Ora la stessa funzionalità dell'esempio di codice sopra può essere ottenuta in Python usando un while
loop come mostrato di seguito.
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 esiste un modo alternativo per implementare la dichiarazione 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()