在Python中是否有goto或任何等价的东西能够跳转到特定的代码行?


当前回答

你可以使用用户定义异常来模拟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()

其他回答

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

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的最佳方式。但是如果你不知道你想用去做什么,就很难给出具体的建议。

@ascobol:

最好的方法是将其包含在函数中或使用异常。对于函数:

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并不适合您。: -)

在执行“goto”时,首先必须问“goto”是什么。虽然看起来很明显,但大多数人都没有考虑goto与函数栈之间的关系。

如果在函数内部执行“goto”,实际上就放弃了函数调用堆栈。这被认为是一种糟糕的做法,因为函数栈的设计期望在委托一个中间任务之后,您将继续您离开的地方。这就是为什么goto用于异常,而异常可以用来模拟goto,我将对此进行解释。

Finite state machines are probably the best use case for goto, which most of the time are implemented in a kludgy way with loops and switch statements, but I believe that "top level" gotos, are the cleanest, most semantic way to implement finite state machines. In this case, you want to make sure, if you have more variables, they are globals, and don't require encapsulation. Make sure you first model your variable state space(which may be different from execution state, ie the finite state machine).

我相信有合理的设计理由使用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)

因此,您可以看到,这在很大程度上是过度思考的,而调用一个函数然后抛出一个错误的helper函数就是您所需要的。您可以将它进一步包装在一个“start”函数中,这样错误就会被捕获,但我认为这并不是严格必要的。虽然其中一些实现可能会耗尽调用堆栈,但第一个运行器示例将其保持为空,如果编译器可以进行尾部调用优化,这也会有所帮助。

Python 2和3

pip3 install goto-statement

在Python 2.6到3.6和PyPy上测试。

链接:转向语句


foo.py

from goto import with_goto

@with_goto
def bar():

    label .bar_begin

    ...

    goto .bar_begin

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

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

else块的缩进是正确的。代码在循环Python语法后使用模糊的else。参见为什么python在for和while循环之后使用'else' ?