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


当前回答

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

def func1():
    print("inside func1")
    def inline():
        print("im inside")
    
    inline()
    
func1()

其他回答

早在2007年,PEP 3136就提出了中断和继续的标签,但被拒绝了。提案的动机部分说明了在Python中模仿带标签的break的几种常见方法(虽然不太优雅)。

我在官方的python设计和历史FAQ中找到了这个。

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

class label(Exception): pass  # declare a label

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

这并不允许你跳到循环的中间,但那是 通常被认为是对goto的滥用。很少使用。

在官方常见问题解答中甚至提到了这一点,并且提供了一个很好的解决方案示例,这非常好。我真的很喜欢python,因为它的社区甚至是这样对待goto的;)

使用评论中@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' ?

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

我最近写了一个函数装饰器,在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。不过,您必须修改字节码。