240

Python 中是否有一个goto或任何等效项能够跳转到特定的代码行?

4

21 回答 21

157

不,Python 不支持标签和 goto。它是一种(高度)结构化的编程语言。

于 2009-01-13T12:55:57.930 回答
100

Python 为您提供了使用一流函数执行 goto 可以执行的一些操作的能力。例如:

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

    label1:
        ...
    label2:
        ...
}

可以像这样在python中完成:

def func1():
    ...

def func2():
    ...

funcmap = {1 : func1, 2 : func2}

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

当然,这不是替代 goto 的最佳方式。但是,如果不确切知道你想用 goto 做什么,很难给出具体的建议。

@阿斯科博尔

您最好的选择是将其包含在函数中或使用异常。对于功能:

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

对于例外:

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

如果你来自另一种编程语言,使用异常来做这样的事情可能会有点尴尬。但我会争辩说,如果你不喜欢使用异常,Python 不适合你。:-)

于 2009-01-13T13:04:56.727 回答
92

我最近写了一个在 Python中启用的函数装饰器goto,就像这样:

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

我不确定为什么有人想做这样的事情。也就是说,我对此并不太认真。但我想指出,这种元编程实际上在 Python 中是可能的,至少在 CPython 和 PyPy 中是可能的,而不仅仅是像其他人那样滥用调试器 API。不过,您必须弄乱字节码。

于 2015-09-20T20:15:04.517 回答
47

我在官方的 python 设计和历史常见问题解答中找到了这个。

为什么没有goto?

您可以使用异常来提供甚至可以跨函数调用工作的“结构化 goto”。许多人认为异常可以方便地模拟 C、Fortran 和其他语言的“go”或“goto”结构的所有合理使用。例如:

class label(Exception): pass  # declare a label

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

这不允许您跳到循环的中间,但这通常被认为是对 goto 的滥用。谨慎使用。

很高兴官方FAQ中甚至提到了这一点,并提供了一个很好的解决方案示例。我真的很喜欢 python,因为它的社区正在goto这样对待;)

于 2017-01-20T16:40:03.950 回答
16

要使用评论中的建议回答@ascobol' 的问题:@bobince

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

块的缩进else是正确的。else该代码在循环 Python 语法之后使用了 obscure 。请参阅为什么 python 在 for 和 while 循环之后使用“else”?

于 2009-01-17T17:42:56.797 回答
15

已经制作了一个工作版本:http: //entrian.com/goto/

注意:它是作为愚人节的玩笑提供的。(虽然工作)

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

不用说。是的,它很有趣,但不要使用它。

于 2015-05-21T11:57:10.013 回答
13

通过一些工作向 python 添加类似“goto”的语句在技术上是可行的。我们将使用“dis”和“new”模块,它们对于扫描和修改python字节码都非常有用。

实现背后的主要思想是首先将代码块标记为使用“goto”和“label”语句。将使用一个特殊的“@goto”装饰器来标记“goto”函数。之后,我们扫描这两个语句的代码,并对底层字节码进行必要的修改。这一切都发生在源代码编译时。

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

希望这能回答这个问题。

于 2015-05-05T10:36:10.190 回答
10

蟒蛇 2 & 3

pip3 install goto-statement

在 Python 2.6 到 3.6 和 PyPy 上进行了测试。

链接:goto语句


foo.py

from goto import with_goto

@with_goto
def bar():

    label .bar_begin

    ...

    goto .bar_begin
于 2019-08-01T17:09:28.890 回答
8

早在 2007 年PEP 3136中就提出了break和的标签,但被拒绝了。提案的动机部分说明了几种常见的(如果不优雅)模仿Python 中标记的方法。continuebreak

于 2012-03-26T22:03:09.047 回答
7

您可以使用用户定义的异常来模拟goto

例子:

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()
于 2015-03-27T16:07:25.853 回答
3

尽管没有任何与goto/labelPython 等效的代码,但您仍然可以获得goto/label使用循环的这种功能。

让我们以下面显示的代码示例为例,其中goto/label可以在除 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...')

现在可以通过使用while循环在 python 中实现上述代码示例的相同功能,如下所示。

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...')
于 2019-12-15T18:13:51.070 回答
3

我一直在寻找类似的东西

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;

所以我的方法是使用布尔值来帮助摆脱嵌套的 for 循环:

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
于 2016-07-07T06:23:05.480 回答
3

您可以使用 python 中的嵌套方法来实现它

def func1():
    print("inside func1")
    def inline():
        print("im inside")
    
    inline()
    
func1()
于 2021-05-27T17:12:49.443 回答
2

现在有。

我认为这可能对您正在寻找的内容有用。

于 2015-09-22T06:33:52.677 回答
1

In lieu of a python goto equivalent I use the break statement in the following fashion for quick tests of my code. This assumes you have structured code base. The test variable is initialized at the start of your function and I just move the "If test: break" block to the end of the nested if-then block or loop I want to test, modifying the return variable at the end of the code to reflect the block or loop variable I'm testing.

def x:
  test = True
  If y:
     # some code
     If test:
            break
  return something
于 2019-01-26T14:17:14.660 回答
1

我想要相同的答案,但我不想使用goto. 所以我使用了以下示例(来自 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)
于 2015-07-30T14:28:19.640 回答
1

对于前向 Goto,您只需添加:

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

不过,这只对简单的场景有帮助(即嵌套这些会让你一团糟)

于 2018-06-02T18:23:07.820 回答
1

在实现“goto”时,首先要问什么是goto。虽然看起来很明显,但大多数人并没有考虑 goto 与函数堆栈的关系。

如果在函数内部执行“goto”,实际上就是放弃了函数调用堆栈。这被认为是不好的做法,因为函数堆栈的设计期望您在委派中间任务后从中断的地方继续。这就是为什么goto用于异常,异常可以用来模拟goto,我会解释。

有限状态机可能是 goto 的最佳用例,大多数情况下它是通过循环和 switch 语句以笨拙的方式实现的,但我相信“顶级” goto 是实现有限状态的最干净、最语义化的方式机器。在这种情况下,您要确保,如果您有更多变量,它们是全局变量,并且不需要封装。确保首先对变量状态空间进行建模(可能与执行状态不同,即有限状态机)。

我相信使用 goto 有合理的设计理由,异常处理是一种特殊情况,将 goto 与函数混合是有意义的。但是,在大多数情况下,您希望将自己限制为“顶级” goto,因此您永远不会在函数内调用 goto,而只能在全局范围内调用。

在现代语言中模拟顶级 goto 的最简单方法是实现顶级 goto,只需要全局变量和空调用堆栈。因此,为了保持调用堆栈为空,每次调用新函数时都会返回。这是打印前 n 个斐波那契数的示例:

a = 0
b = 1
n = 100
def A():
    global a, b
    a = a + b
    n -= 1
    print(a)
    return B() if n > 0 else 0
def B():
    global a, b
    b = a + b
    n -= 1
    print(b)
    return A() if n > 0 else 0
A()

虽然这个例子可能比循环实现更冗长,但它也更加强大和灵活,并且不需要特殊情况。它让您拥有一个完整的有限状态机。您也可以使用 goto 运行器对其进行修改。

def goto(target):
    while(target) target = target()
def A():
    global a, b
    a = a + b
    print(a)
    return B
def B():
    global a, b
    b = a + b
    print(b)
    return A
goto(A)

要强制执行“返回”部分,您可以编写一个 goto 函数,该函数在完成时简单地引发异常。

def goto(target):
    target()
    throw ArgumentError("goto finished.")
def A():
    global a, b
    a = a + b
    print(a)
    goto(B)
def B()
    global a, b
    b = a + b
    print(b)
    goto(A)
goto(A)

所以你看,很多这都是过度思考,而一个调用函数然后抛出错误的辅助函数就是你所需要的。您可以进一步将其包装在“开始”函数中,以便捕获错误,但我认为这不是绝对必要的。虽然其中一些实现可能会用完您的调用堆栈,但第一个运行器示例将其保持为空,并且如果编译器可以进行尾调用优化,那也会有所帮助。

于 2021-10-20T15:11:14.430 回答
1

没有实现 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()  
于 2019-01-31T09:43:31.700 回答
1

我有自己的 goto 方式。我使用单独的 python 脚本。

如果我想循环:

文件1.py

print("test test")
execfile("file2.py")
a = a + 1

文件2.py

print(a)
if a == 10:
   execfile("file3.py")
else:
   execfile("file1.py")

文件3.py

print(a + " equals 10")

注意:此技术仅适用于 Python 2.x 版本)

于 2018-02-18T00:58:11.423 回答
0

我认为while循环是“goto_Statement”的替代品。因为在 3.6 之后 goto 循环不再工作了。我还写了一个while循环的例子。

str1 = "stop"
while str1 == "back":
    var1 = int(input(" Enter Ist Number: "))
    var2 = int(input(" Enter 2nd Number: "))
    var3 = print("""  What is your next operation
                      For Addition   Press And Enter : 'A'
                      For Muliplt    Press And Enter : 'M'
                      For Division   Press And Enter : 'D'
                      For Subtaction Press And Enter : 'S' """)

    var4 = str(input("For operation press any number : "))
    if(var1 == 45) and (var2 == 3):
        print("555")
    elif(var1 == 56) and (var2 == 9):
        print("77")
    elif(var1 == 56) and (var2 == 6):
        print("4")
    else:
        if(var4 == "A" or "a"):
            print(var1 + var2)
        if(var4 == "M" or "m"):
            print(var1 * var2)
        if(var4 == "D" or "d"):
            print(var1 / var2)
        if(var4 == "S" or "s"):
            print(var1 - var2)

    print("if you want to continue then type  'stop'")

    str1 = input()
print("Strt again")    
于 2020-11-27T21:20:40.390 回答