it-swarm.com.de

Gibt es in Python ein Label / goto?

Gibt es ein goto oder eine Entsprechung in Python), um zu einer bestimmten Codezeile springen zu können?

143
user46646

Nein, Python unterstützt keine Labels und goto, wenn Sie danach suchen. Es ist eine (hoch) strukturierte Programmiersprache.

102
unwind

Python bietet Ihnen die Möglichkeit, einige der Dinge zu tun, die Sie mit erstklassigen Funktionen tun können. Zum Beispiel:

void somefunc(int a)
{
    if (a == 1)
        goto label1;
    if (a == 2)
        goto label2;

    label1:
        ...
    label2:
        ...
}

Könnte in python so gemacht werden:

def func1():
    ...

def func2():
    ...

funcmap = {1 : func1, 2 : func2}

def somefunc(a):
    funcmap[a]()  #Ugly!  But it works.

Zugegeben, das ist nicht der beste Weg, um goto zu ersetzen. Aber ohne genau zu wissen, was Sie mit dem goto machen wollen, ist es schwierig, konkrete Ratschläge zu geben.

@ ascobol :

Am besten schließen Sie es in eine Funktion ein oder verwenden eine Ausnahme. Für die Funktion:

def loopfunc():
    while 1:
        while 1:
            if condition:
                return

Für die Ausnahme:

try:
    while 1:
        while 1:
            raise BreakoutException #Not a real exception, invent your own
except BreakoutException:
    pass

Das Verwenden von Ausnahmen für solche Aufgaben kann sich etwas umständlich anfühlen, wenn Sie aus einer anderen Programmiersprache stammen. Aber ich würde argumentieren, dass wenn Sie keine Ausnahmen verwenden möchten, Python ist nicht die Sprache für Sie. :-)

66
Jason Baker

Ich habe kürzlich einen Funktionsdekorator geschrieben, der goto in Python einfach so aktiviert:

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

Ich bin mir nicht sicher, warum man so etwas machen möchte. Das heißt, ich bin nicht zu ernst. Aber ich möchte darauf hinweisen, dass diese Art der Metaprogrammierung in Python tatsächlich möglich ist, zumindest in CPython und PyPy, und nicht nur, indem die Debugger-API als der andere Typ missbraucht wird hat. Sie müssen sich jedoch mit dem Bytecode anlegen.

41
Sebastian Noack

Ich fand dies in der offiziellen python Design and History FAQ .

Warum gibt es kein goto?

Sie können Ausnahmen verwenden, um ein „strukturiertes Goto“ bereitzustellen, das sogar über Funktionsaufrufe hinweg funktioniert. Viele glauben, dass Ausnahmen alle sinnvollen Verwendungen der Konstrukte "go" oder "goto" von C, Fortran und anderen Sprachen nachahmen können. Zum Beispiel:

class label(Exception): pass  # declare a label

try:
    ...
    if condition: raise label()  # goto label
    ...
except label:  # where to goto
    pass
... 

Dies erlaubt es Ihnen nicht, in die Mitte einer Schleife zu springen, aber dies wird normalerweise als Missbrauch von goto angesehen. Sparsam verwenden.

Es ist sehr schön, dass dies sogar in den offiziellen FAQ erwähnt wird und dass ein Nice-Lösungsbeispiel bereitgestellt wird. Ich mag python weil seine Community sogar goto so behandelt;)

21
klaas

So beantworten Sie die Frage @ascobol mithilfe des Vorschlags von @bobince Aus den Kommentaren:

for i in range(5000):
    for j in range(3000):
        if should_terminate_the_loop:
           break
    else: 
        continue # no break encountered
    break

Der Einzug für den Block else ist korrekt. Der Code verwendet obskure else nach einer Python - Schleifensyntax. Siehe Warum verwendet python 'else' nach for- und while-Schleifen?

15
jfs

Eine funktionierende Version wurde erstellt: http://entrian.com/goto/ .

Hinweis: Es wurde als Aprilscherz angeboten. (funktioniert aber)

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

Unnötig zu erwähnen. Ja, es ist lustig, aber benutze es NICHT.

12
harmv

Es ist technisch machbar, python mit einigem Aufwand eine goto-ähnliche Anweisung hinzuzufügen. Wir werden die Module "dis" und "new" verwenden, die beide sehr nützlich sind, um den Byte-Code python zu scannen und zu ändern.

Die Hauptidee der Implementierung besteht darin, einen Codeblock zunächst als "goto" - und "label" -Anweisungen zu kennzeichnen. Ein spezieller "@goto" -Dekorator wird verwendet, um "goto" -Funktionen zu markieren. Anschließend scannen wir diesen Code nach diesen beiden Anweisungen und nehmen die erforderlichen Änderungen am zugrunde liegenden Bytecode vor. Dies alles geschieht zum Zeitpunkt der Kompilierung des Quellcodes.

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

Hoffe das beantwortet die Frage.

7
Rabih Kodeih

Beschriftungen für break und continue wurden bereits 2007 in PEP 3136 vorgeschlagen, aber abgelehnt. Der Abschnitt Motivation des Vorschlags zeigt verschiedene gängige (wenn auch nicht elegante) Methoden zum Imitieren von break in Python.

7
Bill the Lizard

sie können Benutzerdefinierte Ausnahmen verwenden, um goto zu emulieren.

beispiel:

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

Ich habe nach etwas ähnlichem gesucht

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;

Daher bestand mein Ansatz darin, einen Booleschen Wert zu verwenden, um das Ausbrechen aus den verschachtelten for-Schleifen zu unterstützen:

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

Da ist jetzt. gehe z

Ich denke, das könnte nützlich sein für das, wonach Sie suchen.

2
ancho

Ich habe meine eigene Art, gotos zu machen. Ich verwende separate python Skripte.

Wenn ich eine Schleife machen möchte:

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

(HINWEIS: Diese Technik funktioniert nur mit Python 2.x-Versionen)

1
Anonaguy

Ich wollte die gleiche Antwort und ich wollte nicht goto verwenden. Also habe ich folgendes Beispiel verwendet (aus 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

Für ein Forward-Goto können Sie einfach Folgendes hinzufügen:

while True:
  if some condition:
    break
  #... extra code
  break # force code to exit. Needed at end of while loop
#... continues here

Dies hilft jedoch nur in einfachen Szenarien (d. H. Wenn Sie diese verschachteln, geraten Sie in ein Chaos).

0
JGFMK

Python 2 & 3

pip3 install goto-statement

Getestet auf Python 2.6 bis 3.6 und PyPy.

Link: 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.

Anstelle einer python goto-Entsprechung verwende ich die break-Anweisung wie folgt, um meinen Code schnell zu testen. Dies setzt voraus, dass Sie eine strukturierte Codebasis haben. Die Testvariable wird zu Beginn von your initialisiert Funktion und ich verschiebe einfach den Block "If test: break" an das Ende des verschachtelten if-then-Blocks oder der Schleife, die ich testen möchte, und ändere die Rückgabevariable am Ende des Codes so, dass sie die Block- oder Schleifenvariable widerspiegelt, die ich bin testen.

def x:
  test = True
  If y:
     # some code
     If test:
            break
  return something
0
Chris Rogan

nein, es gibt eine alternative Möglichkeit, die goto-Anweisung zu implementieren

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