Python中是否有标签/转到?
在Python中是否有goto
或任何等价物可以跳转到特定的代码行?
不,Python不支持标签和转到,如果这是你的。 这是一个(高度)结构化的编程语言。
Python为您提供了使用第一类函数执行一些可以做的事情的能力。 例如:
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的最好方法。 但是,如果不知道你想要做什么,你很难给出具体的build议。
@ ascobol :
你最好的select是把它放在一个函数中,或者使用一个exception。 对于function:
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
如果来自另一种编程语言,使用exception来做这样的事情可能会感觉有些尴尬。 但是我会争辩说,如果你不喜欢使用exception,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中是实际可行的,至less在CPython和PyPy中,不仅像其他人那样滥用debugging器API, 但是你必须弄乱字节码。
用@bobince
的评论来回答@ascobol
的问题 :
for i in range(5000): for j in range(3000): if should_terminate_the_loop: break else: continue # no break encountered break
虽然我从来没有在实践中看到这样的代码。
已经有一个工作版本: 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"
不用说。 是的,它很有趣,但不要使用它。
PEP 3136在2007年提出了break
和continue
标签,但被拒绝了。 该提议的“ 动机”部分说明了模仿Python中标签break
几种常见(如果不够优雅的)方法。
在技术上可行的做法是在Python中添加一个类似goto的语句。 我们将使用“dis”和“new”模块,对于扫描和修改python字节码非常有用。
实现背后的主要思想是首先将一段代码标记为使用“goto”和“label”语句。 一个特殊的“@goto”装饰器将用于标记“goto”function。 之后,我们扫描这两个语句的代码,并对底层字节代码进行必要的修改。 这一切都发生在源代码编译时。
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()
希望这回答了这个问题。
我在官方的Pythondevise和历史常见问题中发现了这个。
为什么没有转到?
您可以使用exception来提供即使在函数调用中工作的“结构化跳转”。 许多人认为例外可以方便地模拟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中甚至提到了这一点,这是非常好的,并提供了一个很好的解决scheme示例。 我真的很喜欢python,因为它的社区甚至像这样对待goto
;)
我正在寻找类似的东西
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
您可以使用用户定义的例外来模拟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
。 所以我用下面的例子(从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)
现在有了。 去
我认为这可能对你正在寻找的东西有用。