Python中有标签/goto吗?

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

663861 次浏览

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

使用注释中的@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' ?

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

你可以使用用户自定义异常来模拟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”的语句在技术上是可行的。我们将使用"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()

希望这回答了问题。

已经创建了一个工作版本: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"

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

我想要相同的答案,我不想使用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)

我最近在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。不过,您必须修改字节码。

现在有了。转到

我想这可能对你要找的东西有用。

我在找一些类似的东西

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

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

为什么没有goto?

你可以使用异常来提供一个“结构化的goto”,甚至可以工作 跨函数调用。许多人认为异常可以方便地实现 模拟C语言中“go”或“goto”结构的所有合理使用, Fortran和其他语言。例如:< / p >
class label(Exception): pass  # declare a label


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

这不允许你跳到循环中间,但那是 通常被认为是对goto的滥用。谨慎使用。< / p >

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

我有我自己做gotos的方法。 我使用单独的python脚本

如果我想要循环:

file1.py < br >

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

file2.py

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

file3.py

print(a + " equals 10")

此技巧仅适用于Python 2。x版本)

对于一个向前的后藤,你可以添加:

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块或循环的末尾,在代码末尾修改返回变量以反映我正在测试的块或循环变量。

def x:
test = True
If y:
# some code
If test:
break
return something

不,有另一种方法来实现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()

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

虽然在Python中没有任何与goto/label等效的代码,但您仍然可以使用循环获得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...')

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

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...')

我认为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")

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

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

inline()
    

func1()

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

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

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

我相信有合理的设计理由使用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"函数,这样错误就被捕获了,但我不认为这是必要的。虽然其中一些实现可能会耗尽调用堆栈,但第一个运行器示例将其保持为空,如果编译器可以进行尾部调用优化,这也会有所帮助。

我用函数解决了这个问题。我唯一做的就是改变函数的标签。下面是一个非常基本的代码:

def goto_holiday(): #label: holiday
print("I went to holiday :)")
    

def goto_work(): #label: work
print("I went to work")
salary=5000
if salary>6000:
goto_holiday()
else:
goto_work()