`Python中的goto`

`Python中的goto`,python,compilation,bytecode,goto,Python,Compilation,Bytecode,Goto,我必须在Python中使用goto。我发现,但是我的Python实现(Mac上的CPython 2.7.1)没有这个模块,所以它似乎不可移植。它至少应该在所有支持CPython字节码的Python实现中工作(特别是我关心CPython和PyPy)。还有,还有。下面给出了答案 我可以手动构建字节码(即编写自己的Python编译器),因为有这样一条指令(JUMP\u ABSOLUTE和friends)。但我想知道是否有更简单的方法。是否可以通过inspect等方式调用单个字节码指令?我还考虑过通过P

我必须在Python中使用
goto
。我发现,但是我的Python实现(Mac上的CPython 2.7.1)没有这个模块,所以它似乎不可移植。它至少应该在所有支持CPython字节码的Python实现中工作(特别是我关心CPython和PyPy)。还有,还有。下面给出了答案

我可以手动构建字节码(即编写自己的Python编译器),因为有这样一条指令(
JUMP\u ABSOLUTE
和friends)。但我想知道是否有更简单的方法。是否可以通过
inspect
等方式调用单个字节码指令?我还考虑过通过Python进行编译,然后自动修补生成的Python字节码



当然,人们会问为什么,如果我不解释为什么我真的需要这个,他们不会给我任何有用的答案。简而言之,我的用例是:我正在将C AST翻译成Python AST并编译它。我可以以某种方式将每个逻辑流(所有循环和其他内容)映射到等价的Python代码。除了转到之外的所有内容。相关项目:(请参阅),。

您可能拥有我见过的唯一一个有效的用例,用于在Python中使用
goto
。:-)

在Python中模拟forward
goto
最直接的方法是使用异常,因为这些异常可以跳出嵌套控制结构的任何深度

class Goto(Exception):
    pass

try:
    if foo = "bar":
        raise Goto
    print "foo is not bar"
except Goto:
    print "foo is bar"
如果您需要支持多个目的地,这会很麻烦,但我认为可以使用嵌套的
try/except
结构和多个异常类来实现,每个目的地一个异常类。由于C将
goto
限制在单个函数的范围内,至少您不必担心如何跨函数执行此操作。:-)当然,它不适用于反向
goto
s

另一件需要注意的事情是,Python中的异常虽然比某些语言快,但仍然比正常的流控制结构(如
while
for
)慢


这可能需要大量的工作(虽然可能不会比您已经准备的更多),但是如果您可以生成Python字节码而不是Python源代码,那么实现
goto
,就不会有问题,因为Python字节码(像大多数psuedo机器语言一样)有一个完美的cromultent
JUMP\u ABSOLUTE
操作码。

使用
goto
的代码可能会遵循一些常见的模式

在大多数情况下,我怀疑所有goto语句都会跳转到一个更晚的位置,并且在一个更封闭的块中;如果函数体完全遵循此模式,则将goto转换为异常,并将标签作为except块

在同一块中从一个地方跳到另一个地方的其他情况,如在状态机中使用的情况。这可能转化为调度循环;标签和下一个标签之间的每个区域都成为一个函数;goto被替换为
next_state='labelname';返回


最后一种情况是跳转进入一个循环体时,这两种情况都不是上述情况,也可能是非常重要的。我还没有答案。

我知道每个人都在想什么:

然而,在某些教学案例中,您可能确实需要一个
goto

这个python配方提供了
goto
命令作为函数装饰器

(卡尔·切瑞克的Python配方)

如果你厌倦了汽车的缓慢速度,这就是你的食谱 现有的
goto
模块。本节中的
goto
配方大约快60倍,而且更干净(滥用
sys.settrace
似乎不太像蟒蛇)。因为这是一个装饰器,它会提醒 读卡器哪些函数使用
goto
。它不实现comefrom 命令,尽管扩展它并不困难(练习 (供读者阅读)。此外,不支持计算GOTO;他们不是 蟒蛇的

  • 使用
    dis.dis(fn)
    显示函数的字节码反汇编
  • 函数的字节码由
    fn.func\u code.co\u code
    访问。 这是只读的,因此:
  • 装饰功能的创建与旧功能完全相同, 但是字节码被更新以遵守
    goto
    命令
  • 这只是2.x;新模块不在Python3.x中(另一个版本) 读者练习!)
用法

@goto
def test1(n):
    s = 0

    label .myLoop

    if n <= 0:
        return s
    s += n
    n -= 1

    goto .myLoop

>>> test1(10)
55
@goto
def测试1(n):
s=0
label.myLoop
如果n>>测试1(10)
55

更新

@goto
def test1(n):
    s = 0

    label .myLoop

    if n <= 0:
        return s
    s += n
    n -= 1

    goto .myLoop

>>> test1(10)
55
以下是与Python 3兼容的两个附加实现:


    • 这不是你想要的,但请听我说

      很多年前,我和儿子用BASIC写了一个“冒险”游戏。地下游戏中的每个位置都有一个行号。例如,当你通过向北的隧道离开一个地点时,你到达了另一个地点

      编码类似于
      if response==“N”GOTO 2400
      。所以玩家们最终使用GOTOs到处游荡

      我想知道如何在Python中实现这一点,并提出了这个方法

      也许这种技术可以用于其他需要GOTO之类的应用程序。如果你把你的程序分割成块,这些块是函数,下面的“有点傻”的编码就可以了

      """ Simple, short and unfinished 'Adventure' game to show how a program such
      as this with 'locations' (where each location is handled by a function) can
      simulate 'GOTO's through use of the eval() function. Each time the player
      chooses an exit from his current location, where he goes to will depend on the
      exit chosen and achieved using eval() on the last line.
      
      This saves having to code a series of 'if's at each location which call the
      correct function the player goes to. Also, because the code always comes back
      to the eval line at the botton each time, one location's function doesn't call
      the next location's function, with possible risk of stack overflow if the
      program is radically extended.
      
      The program uses randint() to determine if characters are there and what they
      are doing. This is just a taster. Dramatic improvements could be made if the
      player could collect and use artefacts found during his travels. For instance
      if there was a key somewhere and it was collected, it could be used to unlock
      the door, but the key can't be picked up unless the troll isn't there etc.
      The program needs to be able to parse (understand) simple natural language
      (English) commands such as 'take key' or 'unlock door' or 'give food to troll'
      There will also need to be some global variables so each function can behave
      and do stuff dependent on these variables.
      
      The program needs to be able to respond to players' commands, such as after a
      player has indicated which direction he wants to go, the program responds,
      'You can't go that way. the Ork is blocking your path'. You get the picture.
      
      The program also needs to be able to save variables in a dictionary (which is
      then pickled into a file) so players can close the game and save it and pick up
      where they left off next time.
      
      People new to this sort of game should realise by the way, that just because
      a tunnel (or other route) leaves one location northwards, that doesn't mean
      that it arrives at the next location from the south. The tunnels twist and
      turn all over the place."""
      
      
      def l0():
          #print('L0')
          print("You're south of a forbidding-looking cave")
          go = input('n or q > ')
          if go == 'n': return('1')
          if go == 'q': return('q')
          else: return 'q'
      
      def l1():
          #print('L1')
          print("You're in a large, dark cave. Bats are hanging from the ceiling.")
          print("Tunnels lead north, east and west. The entrance is south of you.")
          go = input('n s e w > ')
          if go == 'n': return('3') # Leaving L1 northwards takes you to L3
          if go == 's': return('0') # Leaving L1 southwards takes you to L0
          if go == 'e': return('3') # Leaving L1 eastwards also takes you to L3
          if go == 'w': return('2') # Leaving L1 westwards takes you to L2
          else: return 'q'
      
      def l2():
          #print('L2')
          print("You've come to a bridge running east across a chasm")
          print("On the other side the only way to go is through a tunnel")
          print("This side of the chasm, a tunnel leads north and a path leads south")
          go = input('n e s > ')
          if go == 'n': return('1') # As per L! but applicable to L2 etc.
          if go == 'e': return('4')
          if go == 's': return('3')
          else: return 'q'
      
      def l3():
          #print('L3')
          print("You've come to a hot and humid cavern")
          print("Tunnels run north, east and west. A path leads south.")
          print("There's a dragon here.")
          dstate = randint(1,5)
          if dstate == 1: print("The dragon seems to be asleep")
          if dstate == 2: print("The dragon looks sleepy")
          if dstate == 3: print("The dragon is awake")
          if dstate == 4: print("The dragon looks angry")
          if dstate == 5: print("The dragon is breathing fire and very angry!")
          go = input('n s e w > ')
          if go == 'n': return('1')
          if go == 's': return('2')
          if go == 'e': return('4')
          if go == 'w': return('1')
          else: return 'q'
      
      def l4():
          #print('L4')
          print("You've arrived at a grotto. There are jewels here!")
          tstate = randint(1,4)
          if tstate > 1: print("There's a troll here wielding a cudgel")
          print("Tunnels lead east, west and south from here")
          go = input('s e w > ')
          if go == 's': return('5')
          if go == 'e': return('2')
          if go == 'w': return('3')
          else: return 'q'
      
      def l5():
          #print('L5')
          print("The tunnel ends at a door leading to a small room")
          print("Through a grille in the door, you can see there is no way out")
          print("The only way is back, south along the tunnel")
          print("But there's gold in the room!")
          print("The door is locked.")
          go = input('s > ')
          if go == 's': return('4')
          else: return 'q'
      
      ### ********************* Main Program Start ***************************
      
      import random
      from random import randint
      
      go = l0()   # That's call L zero (location zero), not ten!
      
      while go != 'q':
          print()
          go = eval("l"+go+"()")  # Program always returns here to sort out where to
                                  # go next. Player doesn't of course!
      

      我已经为Python3更新了python goto装饰器。你可以在。使用goto代替函数可以使状态机的速度提高5倍左右


      python 2的版本在上仍然可用,但它有许多在python 3版本中修复的错误。

      已经制作了一个工作版本:

      注:这是一个愚人节玩笑。(尽管如此)


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

      将C翻译成Python?世界跆拳道联盟。只是为什么会这样