Existe-t-il un goto
ou un équivalent en Python pour pouvoir accéder à une ligne de code spécifique?
goto
en Python quand il traduisait du code Fortran en Python. Il se détestait pour ça.
Existe-t-il un goto
ou un équivalent en Python pour pouvoir accéder à une ligne de code spécifique?
goto
en Python quand il traduisait du code Fortran en Python. Il se détestait pour ça.
Réponses:
Non, Python ne prend pas en charge les étiquettes et goto, si c'est ce que vous recherchez. C'est un langage de programmation (hautement) structuré.
Python vous offre la possibilité de faire certaines des choses que vous pourriez faire avec un goto en utilisant des fonctions de première classe. Par exemple:
void somefunc(int a)
{
if (a == 1)
goto label1;
if (a == 2)
goto label2;
label1:
...
label2:
...
}
Cela pourrait être fait en python comme ceci:
def func1():
...
def func2():
...
funcmap = {1 : func1, 2 : func2}
def somefunc(a):
funcmap[a]() #Ugly! But it works.
Certes, ce n'est pas la meilleure façon de remplacer goto. Mais sans savoir exactement ce que vous essayez de faire avec le goto, il est difficile de donner des conseils précis.
@ ascobol :
Votre meilleur pari est de l'enfermer dans une fonction ou d'utiliser une exception. Pour la fonction:
def loopfunc():
while 1:
while 1:
if condition:
return
Pour l'exception:
try:
while 1:
while 1:
raise BreakoutException #Not a real exception, invent your own
except BreakoutException:
pass
Utiliser des exceptions pour faire des choses comme celle-ci peut sembler un peu gênant si vous venez d'un autre langage de programmation. Mais je dirais que si vous n'aimez pas utiliser les exceptions, Python n'est pas le langage qu'il vous faut. :-)
loopfunc
nécessitera généralement des contributions et un peu plus d'efforts à mettre en œuvre, mais c'est le meilleur moyen dans la plupart des cas, je pense.
J'ai récemment écrit un décorateur de fonctions qui permet goto
en Python, comme ça:
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
Je ne sais pas pourquoi on aimerait faire quelque chose comme ça. Cela dit, je ne suis pas trop sérieux à ce sujet. Mais j'aimerais souligner que ce type de métaprogrammation est réellement possible en Python, au moins en CPython et PyPy, et pas seulement en abusant de l'API du débogueur comme l'a fait cet autre gars . Vous devez cependant jouer avec le bytecode.
.begin
et les .end
étiquettes?
J'ai trouvé cela dans la FAQ officielle sur la conception et l'histoire de python .
Pourquoi n'y a-t-il pas de goto?
Vous pouvez utiliser des exceptions pour fournir un «goto structuré» qui fonctionne même entre les appels de fonction. Beaucoup pensent que les exceptions peuvent facilement émuler toutes les utilisations raisonnables des constructions «go» ou «goto» de C, Fortran et d'autres langages. Par exemple:
class label(Exception): pass # declare a label
try:
...
if condition: raise label() # goto label
...
except label: # where to goto
pass
...
Cela ne vous permet pas de sauter au milieu d'une boucle, mais c'est généralement considéré comme un abus de goto de toute façon. Utiliser avec parcimonie.
C'est très bien que cela soit même mentionné dans la FAQ officielle et qu'un bel exemple de solution soit fourni. J'aime vraiment python parce que sa communauté traite même goto
comme ça;)
goto
est un problème majeur de programmation, bien sûr, mais l'OMI abuser des exceptions pour émuler goto
n'est que légèrement mieux et devrait encore être fortement désapprouvé. J'aurais préféré que les créateurs de Python incluent goto
dans le langage pour les rares occasions où cela est réellement utile que de l'interdire parce que "c'est mauvais, les gars" et puis recommander d'abuser des exceptions pour obtenir la même fonctionnalité (et la même spaghettification du code).
Pour répondre à la @ascobol
question de en utilisant @bobince
la suggestion de dans les commentaires:
for i in range(5000):
for j in range(3000):
if should_terminate_the_loop:
break
else:
continue # no break encountered
break
Le retrait du else
bloc est correct. Le code utilise obscure else
après une syntaxe Python en boucle. Voir Pourquoi python utilise-t-il 'else' après les boucles for et while?
else
est exécuté après la boucle s'il break
n'a pas été rencontré. L'effet est que should_terminate_the_loop
termine les boucles internes et externes.
return
suggéré par @Jason Baker est une bonne alternative pour sortir de boucles profondément imbriquées.
Une version fonctionnelle a été créée: http://entrian.com/goto/ .
Remarque: il s'agissait d'une blague du poisson d'avril. (fonctionne bien)
# 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"
Il va sans dire. Oui c'est drôle, mais ne l'utilisez pas.
Des étiquettes pour break
et continue
ont été proposées dans PEP 3136 en 2007, mais elles ont été rejetées. La section Motivation de la proposition illustre plusieurs méthodes courantes (si inélégantes) pour imiter étiquetées break
en Python.
Il est techniquement possible d'ajouter une instruction de type «goto» à python avec un peu de travail. Nous utiliserons les modules "dis" et "new", tous deux très utiles pour scanner et modifier le code octet python.
L'idée principale derrière l'implémentation est de marquer d'abord un bloc de code comme utilisant des instructions "goto" et "label". Un décorateur spécial "@goto" sera utilisé pour marquer les fonctions "goto". Ensuite, nous analysons ce code pour ces deux instructions et appliquons les modifications nécessaires au code d'octet sous-jacent. Tout cela se produit au moment de la compilation du code source.
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()
J'espère que cela répond à la question.
vous pouvez utiliser des exceptions définies par l'utilisateur pour émulergoto
exemple:
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
Testé sur Python 2.6 à 3.6 et PyPy.
Lien: goto-statement
foo.py
from goto import with_goto
@with_goto
def bar():
label .bar_begin
...
goto .bar_begin
Je cherchais quelque chose de similaire à
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;
Mon approche a donc été d'utiliser un booléen pour aider à sortir des boucles for imbriquées:
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
Je voulais la même réponse et je ne voulais pas l'utiliser goto
. J'ai donc utilisé l'exemple suivant (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)
J'ai ma propre façon de faire des gotos. J'utilise des scripts python séparés.
Si je veux faire une boucle:
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")
( REMARQUE: cette technique ne fonctionne que sur les versions Python 2.x)
Pour un aller en avant, vous pouvez simplement ajouter:
while True:
if some condition:
break
#... extra code
break # force code to exit. Needed at end of while loop
#... continues here
Cela n'aide cependant que pour des scénarios simples (c'est-à-dire que leur imbrication vous mettrait dans le désordre)
Au lieu d'un équivalent python goto, j'utilise l'instruction break de la manière suivante pour des tests rapides de mon code. Cela suppose que vous disposez d'une base de code structurée. La variable de test est initialisée au début de votre fonction et je déplace simplement le bloc "If test: break" à la fin du bloc ou de la boucle imbriquée if-then que je veux tester, en modifiant la variable de retour à la fin du code pour refléter la variable de bloc ou de boucle que je teste.
def x:
test = True
If y:
# some code
If test:
break
return something
Bien qu'il n'y ait pas de code équivalent à goto/label
Python, vous pouvez toujours obtenir une telle fonctionnalité en goto/label
utilisant des boucles.
Prenons un exemple de code ci-dessous où goto/label
peut être utilisé dans un langage arbitraire autre que 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...')
Maintenant, la même fonctionnalité de l'exemple de code ci-dessus peut être obtenue en python en utilisant une while
boucle comme indiqué ci-dessous.
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...')
non il existe une autre façon d'implémenter l'instruction 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()