Python 中是否有一个goto
或任何等效项能够跳转到特定的代码行?
21 回答
不,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 的最佳方式。但是,如果不确切知道你想用 goto 做什么,很难给出具体的建议。
@阿斯科博尔:
您最好的选择是将其包含在函数中或使用异常。对于功能:
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。不过,您必须弄乱字节码。
我在官方的 python 设计和历史常见问题解答中找到了这个。
为什么没有goto?
您可以使用异常来提供甚至可以跨函数调用工作的“结构化 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
...
这不允许您跳到循环的中间,但这通常被认为是对 goto 的滥用。谨慎使用。
很高兴官方FAQ中甚至提到了这一点,并提供了一个很好的解决方案示例。我真的很喜欢 python,因为它的社区正在goto
这样对待;)
要使用评论中的建议回答@ascobol
' 的问题:@bobince
for i in range(5000):
for j in range(3000):
if should_terminate_the_loop:
break
else:
continue # no break encountered
break
块的缩进else
是正确的。else
该代码在循环 Python 语法之后使用了 obscure 。请参阅为什么 python 在 for 和 while 循环之后使用“else”?
已经制作了一个工作版本: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"
不用说。是的,它很有趣,但不要使用它。
通过一些工作向 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()
希望这能回答这个问题。
蟒蛇 2 & 3
pip3 install goto-statement
在 Python 2.6 到 3.6 和 PyPy 上进行了测试。
链接:goto语句
foo.py
from goto import with_goto
@with_goto
def bar():
label .bar_begin
...
goto .bar_begin
早在 2007 年PEP 3136中就提出了break
和的标签,但被拒绝了。提案的动机部分说明了几种常见的(如果不优雅)模仿Python 中标记的方法。continue
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()
尽管没有任何与goto/label
Python 等效的代码,但您仍然可以获得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...')
现在可以通过使用while
循环在 python 中实现上述代码示例的相同功能,如下所示。
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...')
我一直在寻找类似的东西
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 中的嵌套方法来实现它
def func1():
print("inside func1")
def inline():
print("im inside")
inline()
func1()
现在有。去
我认为这可能对您正在寻找的内容有用。
In lieu of a python goto equivalent I use the break statement in the following fashion for quick tests of my code. This assumes you have structured code base. The test variable is initialized at the start of your function and I just move the "If test: break" block to the end of the nested if-then block or loop I want to test, modifying the return variable at the end of the code to reflect the block or loop variable I'm testing.
def x:
test = True
If y:
# some code
If test:
break
return something
我想要相同的答案,但我不想使用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)
对于前向 Goto,您只需添加:
while True:
if some condition:
break
#... extra code
break # force code to exit. Needed at end of while loop
#... continues here
不过,这只对简单的场景有帮助(即嵌套这些会让你一团糟)
在实现“goto”时,首先要问什么是goto。虽然看起来很明显,但大多数人并没有考虑 goto 与函数堆栈的关系。
如果在函数内部执行“goto”,实际上就是放弃了函数调用堆栈。这被认为是不好的做法,因为函数堆栈的设计期望您在委派中间任务后从中断的地方继续。这就是为什么goto用于异常,异常可以用来模拟goto,我会解释。
有限状态机可能是 goto 的最佳用例,大多数情况下它是通过循环和 switch 语句以笨拙的方式实现的,但我相信“顶级” goto 是实现有限状态的最干净、最语义化的方式机器。在这种情况下,您要确保,如果您有更多变量,它们是全局变量,并且不需要封装。确保首先对变量状态空间进行建模(可能与执行状态不同,即有限状态机)。
我相信使用 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)
所以你看,很多这都是过度思考,而一个调用函数然后抛出错误的辅助函数就是你所需要的。您可以进一步将其包装在“开始”函数中,以便捕获错误,但我认为这不是绝对必要的。虽然其中一些实现可能会用完您的调用堆栈,但第一个运行器示例将其保持为空,并且如果编译器可以进行尾调用优化,那也会有所帮助。
没有实现 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()
我有自己的 goto 方式。我使用单独的 python 脚本。
如果我想循环:
文件1.py
print("test test")
execfile("file2.py")
a = a + 1
文件2.py
print(a)
if a == 10:
execfile("file3.py")
else:
execfile("file1.py")
文件3.py
print(a + " equals 10")
(注意:此技术仅适用于 Python 2.x 版本)
我认为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")