web-dev-qa-db-fra.com

Existe-t-il un label / goto en Python?

Existe-t-il un goto ou un équivalent dans Python pour pouvoir passer à une ligne de code spécifique?

143
user46646

Non, Python ne prend pas en charge les étiquettes et allez-y, si c'est ce que vous cherchez. C'est un langage de programmation (hautement) structuré.

102
unwind

Python vous offre la possibilité de faire certaines choses 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:
        ...
}

Pourrait être fait dans 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 spécifiques.

@ ascobol :

Votre meilleur choix est de l'inclure 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 de telles choses 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 la langue pour vous. :-)

66
Jason Baker

J'ai récemment écrit un décorateur de fonctions qui active goto en Python, juste 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 je tiens à souligner que ce type de méta-programmation est réellement possible en Python, du moins dans CPython et PyPy, et pas seulement en utilisant à mauvais escient l’API du débogueur comme cela autre type l’a fait. Cependant, vous devez jouer avec le bytecode.

41
Sebastian Noack

J'ai trouvé cela dans la FAQ officielle python Conception et historique .

Pourquoi n'y a-t-il pas de goto?

Vous pouvez utiliser des exceptions pour fournir un "goto structuré" qui fonctionne même pour les appels de fonction. Beaucoup pensent que les exceptions peuvent facilement imiter toutes les utilisations raisonnables des constructions "aller" ou "aller" des langages C, Fortran et autres. 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 vous placer au milieu d’une boucle, mais c’est généralement considéré comme un abus de goto. Utiliser avec parcimonie.

C'est très gentil que cela soit même mentionné dans la FAQ officielle et qu'un exemple de solution Nice soit fourni. J'aime beaucoup python parce que sa communauté traite même goto comme ceci;)

21
klaas

Pour répondre à la question question de @ascobol en utilisant la suggestion de @bobince à partir des 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 bloc else est correct. Le code utilise obscure else après une syntaxe de boucle Python. Voir Pourquoi python utilise-t-il 'else' après les boucles for et while?

15
jfs

Une version de travail a été faite: http://entrian.com/goto/ .

Remarque: il s'agissait d'une blague du poisson d'avril. (travaille 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.

12
harmv

Il est techniquement possible d’ajouter une tâche similaire à python. Nous allons utiliser les modules "dis" et "new", tous deux très utiles pour scanner et modifier le code python.

L'idée principale derrière l'implémentation est de commencer par marquer un bloc de code en utilisant les 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 passe à 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 __== '__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.

7
Rabih Kodeih

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 elles sont inélégantes) pour imiter le libellé break en Python.

7
Bill the Lizard

vous pouvez utiliser Exceptions définies par l'utilisateur pour émuler goto

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()
4
xavierskip

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 consistait donc à utiliser un booléen pour aider à sortir de la boucle imbriquée:

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
yaitloutou

Il y a maintenant. goto

Je pense que cela pourrait être utile pour ce que vous recherchez.

2
ancho

J'ai ma propre façon de faire des gotos. J'utilise des scripts python distincts.

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")

(NOTE: Cette technique ne fonctionne que sur les versions Python 2.x)

1
Anonaguy

Je voulais la même réponse et je ne voulais pas utiliser goto. J'ai donc utilisé l'exemple suivant (tiré 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)
1
Sand1512

Pour un Goto 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 que pour des scénarios simples (c’est-à-dire qu’ils seraient imbriqués).

0
JGFMK

Python 2 et 3

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(start, stop):

    label .bar_begin

    ...

    goto .bar_begin
0
Marco D.G.

Au lieu d'un équivalent python, j'utilise l'instruction break de la manière suivante pour effectuer des tests rapides de mon code. Cela suppose que vous ayez une base de code structurée. La variable de test est initialisée au début de votre fonction et je déplace juste le bloc "If test: break" à la fin du bloc imbriqué if-then ou de la boucle 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
0
Chris Rogan

non, il existe un autre moyen 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()  
0
Python Experts