goto
Python中是否有一个或任何等价物能够跳转到特定的代码行?
不,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做什么,很难给出具体的建议.
@ 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就不适合您.:-)
我最近写了一个函数装饰器,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
我不确定为什么人们会这样做.那就是说,我对此并不太认真.但是我想指出,这种元编程在Python中是可行的,至少在CPython和PyPy中,并且不仅仅是像其他人那样滥用调试器API .你必须弄乱字节码.
我在官方的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 ...
这不允许你跳到循环的中间,但这通常被认为是滥用goto.谨慎使用.
在官方常见问题解答中甚至提到这一点非常好,并且提供了一个很好的解决方案示例.我真的很喜欢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语法之后使用模糊.看看为什么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"
不用说.是的它有趣,但不要使用它.
2007年在PEP 3136中提出break
并continue
提出了标签,但遭到拒绝.该提案的Motivation部分说明了几种常用(如果不优雅)模仿Python中标记的方法.break
通过一些工作向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()
希望这能回答这个问题.