Python中有标签/ goto吗?

Is there a label/goto in Python?

Python中是否有goto或任何等价物才能跳转到特定的代码行?


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


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

1
2
3
4
5
6
7
8
9
10
11
12
void somefunc(int a)
{
    if (a == 1)
        goto label1;
    if (a == 2)
        goto label2;

    label1:
        ...
    label2:
        ...
}

可以像这样在python中完成:

1
2
3
4
5
6
7
8
9
10
def func1():
    ...

def func2():
    ...

funcmap = {1 : func1, 2 : func2}

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

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

@ascobol:

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

1
2
3
4
5
def loopfunc():
    while 1:
        while 1:
            if condition:
                return

对于例外:

1
2
3
4
5
6
try:
    while 1:
        while 1:
            raise BreakoutException #Not a real exception, invent your own
except BreakoutException:
    pass

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


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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。你必须弄乱字节码。


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

Why is there no goto?

You can use exceptions to provide a"structured goto" that even works
across function calls. Many feel that exceptions can conveniently
emulate all reasonable uses of the"go" or"goto" constructs of C,
Fortran, and other languages. For example:

1
2
3
4
5
6
7
8
9
class label(Exception): pass  # declare a label

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

This doesn’t allow you to jump into the middle of a loop, but that’s
usually considered an abuse of goto anyway. Use sparingly.

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


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

1
2
3
4
5
6
7
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'?


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

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

1
2
3
4
5
6
7
8
9
10
11
12
# 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
"

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


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


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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
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()

希望这能回答这个问题。


您可以使用用户定义的例外来模拟goto

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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()


我正在寻找类似的东西

1
2
3
4
5
6
7
8
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循环中脱离出来:

1
2
3
4
5
6
7
8
9
10
11
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

现在有。去

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


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

如果我想循环:

file1.py

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

file2.py

1
2
3
4
5
print(a)
if a == 10:
   execfile("file3.py")
else:
   execfile("file1.py")

file3.py

1
print(a +" equals 10")

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


我想要相同的答案,我不想使用goto。所以我使用了以下示例(来自learnpythonthehardway)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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)

Python 2和3

1
pip3 install goto-statement

Tested on Python 2.6 through 3.6 and PyPy.

链接:goto语句

foo.py

1
2
3
4
5
6
7
8
9
10
from goto import with_goto

@with_goto
def bar(start, stop):

    label .bar_begin

    ...

    goto .bar_begin

对于转发Goto,您可以添加:

1
2
3
4
5
6
while True:
  if some condition:
    break
  #... extra code
  break # force code to exit. Needed at end of while loop
#... continues here

这只会对简单的场景有所帮助(即嵌套这些会让你陷入混乱)


代替python goto等价物,我使用以下方式的break语句来快速测试我的代码。 这假设您有结构化代码库。 测试变量在函数开始时初始化,我只是将"If test:break"块移动到我想测试的嵌套if-then块或循环的末尾,修改代码末尾的返回变量 反映我正在测试的块或循环变量。

1
2
3
4
5
6
7
def x:
  test = True
  If y:
     # some code
     If test:
            break
  return something


没有另一种方法来实现goto语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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()