Python中有标签/ goto吗?

use*_*646 154 python goto

gotoPython中是否有一个或任何等价物能够跳转到特定的代码行?

unw*_*ind 107

不,Python不支持标签和goto,如果这是您所追求的.它是一种(高度)结构化的编程语言.

  • @rejinacm的功能? (35认同)
  • 我觉得“高度结构化”可能有点言过其实了。 (11认同)
  • 将代码重构为函数并执行返回 (4认同)

Jas*_*ker 67

Python为您提供了使用第一类函数执行goto所能完成的一些功能.例如:

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

    label1:
        ...
    label2:
        ...
}
Run Code Online (Sandbox Code Playgroud)

可以像这样在python中完成:

def func1():
    ...

def func2():
    ...

funcmap = {1 : func1, 2 : func2}

def somefunc(a):
    funcmap[a]()  #Ugly!  But it works.
Run Code Online (Sandbox Code Playgroud)

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

@ ascobol:

最好的办法是将其包含在函数中或使用异常.对于功能:

def loopfunc():
    while 1:
        while 1:
            if condition:
                return
Run Code Online (Sandbox Code Playgroud)

对于例外:

try:
    while 1:
        while 1:
            raise BreakoutException #Not a real exception, invent your own
except BreakoutException:
    pass
Run Code Online (Sandbox Code Playgroud)

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

  • 抱歉,异常不应该用于以这种方式控制程序流程。 (7认同)

Seb*_*ack 47

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

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
Run Code Online (Sandbox Code Playgroud)

我不确定为什么人们会这样做.那就是说,我对此并不太认真.但是我想指出,这种元编程在Python中是可行的,至少在CPython和PyPy中,并且不仅仅是像其他人那样滥用调试器API .你必须弄乱字节码.

  • 你做的很棒的装饰!很棒,如何摆弄字节码:-) (2认同)

kla*_*aas 21

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

为什么没有转到?

您可以使用异常来提供甚至可以跨函数调用工作的"结构化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
... 
Run Code Online (Sandbox Code Playgroud)

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

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

  • 毫无疑问,滥用“goto”是一个主要的编程问题,但在我看来,滥用异常来模拟“goto”只是稍微好一点,但仍然应该受到强烈反对。我宁愿Python的创建者在语言中包含“goto”,因为它实际上是有用的,而不是因为“这很糟糕,伙计们”而禁止它,然后建议滥用异常来获得相同的功能(和相同的代码)意大利面化)。 (4认同)

jfs*_*jfs 15

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

for i in range(5000):
    for j in range(3000):
        if should_terminate_the_loop:
           break
    else: 
        continue # no break encountered
    break
Run Code Online (Sandbox Code Playgroud)

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

  • @ B1KMusic:缩进是正确的.这是一种特殊的Python语法.如果没有遇到`break`,则在循环*之后执行`else`.结果是`should_terminate_the_loop`终止了*内部和外部循环. (3认同)
  • @B1KMusic:不。复制代码来解决你的无知不是一个好的解决方案。是的。`return` [由@Jason Baker 建议](http://stackoverflow.com/a/438869/4279) 是打破深度嵌套循环的一个很好的选择。 (2认同)

har*_*rmv 12

已经制作了一个工作版本: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"
Run Code Online (Sandbox Code Playgroud)

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

  • 对我来说看起来比使用 3 个中断更好......当然还有其他方法可以编写它。 (3认同)

Mar*_*.G. 8

蟒蛇 2 & 3

pip3 install goto-statement
Run Code Online (Sandbox Code Playgroud)

在 Python 2.6 到 3.6 和 PyPy 上测试。

链接:goto 语句


文件

from goto import with_goto

@with_goto
def bar():

    label .bar_begin

    ...

    goto .bar_begin
Run Code Online (Sandbox Code Playgroud)


Bil*_*ard 7

2007年在PEP 3136中提出breakcontinue提出了标签,但遭到拒绝.该提案的Motivation部分说明了几种常用(如果不优雅)模仿Python中标记的方法.break


xav*_*kip 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()
Run Code Online (Sandbox Code Playgroud)


Rab*_*eih 7

通过一些工作向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()
Run Code Online (Sandbox Code Playgroud)

希望这能回答这个问题.