82870034 发表于 2015-4-22 07:03:16

Python programming with goto

  豆瓣Python版有人想要goto。虽说看不出来goto有什么特别吸引力,但是为了实现Python社区对广大人民群众做出的“Python是世界上除Lisp外最牛b的编程语言”的庄严承诺,同时也为了复习一下一段时间没用Python知识,写了一个goto模块。使用如下例:



1 from goto import *
2
3 @patch
4 def f2():
5   goto(10)
6   print 'should not see this'
7   label(10)
8   for i in range(1,99999):
9         print i
10         if i == 5:
11             goto('out')
12   label('out')
13
14 f2()  用法是:

  1. from goto import *。注意暂时不支持import goto,不是不能实现,是暂时没时间写。
  2.对需要使用goto的函数,前面加个@patch
  3.用label(x)和goto(x)的形式写label和goto。x可以是数字或字符串。

  goto模块的代码如下:


goto.py

import dis,pdb
#dummy functions serving as target of bytecode patching
def goto(label):
    pass
def label(label):
    pass
#
def decode_bytecode(fun):
    """Input: a function
       Ouput: a list of pairs (opcode, arguments)"""
    c = fun.func_code.co_code
    n = len(c)
    i = 0
    while i < n:
      op = c
      i += 1
      arguments = ""
      if ord(op) >= dis.HAVE_ARGUMENT:
            arguments = c
            i += 2
      yield (op, arguments)
def sample():
    goto(200)
    if 1 == 2:
      sample()
    else:
      print 'sample'
      
def test_decode(fun):
    for op,arg in decode_bytecode(fun):
      if arg=='':
            print dis.opname
      else:
            print dis.opname +' '+str(ord(arg))+' '+str(ord(arg))
      
def match_pattern(seq, i, p):
    """
    try to match pattern p to seq, return None if match failed
    seq: output of decode_bytecode
    p ->
    instr -> (opcode, arg, arg)      opcode is a opcode string
    arg -> ''                        I don't give a damn about this arg
    arg -> integer                   match arg with number
    arg -> string                  the arg is key of the returned match dict from which the arg value can be extracted
    arg -> lambda                  lambda is evaluated with the argument, false return means failed match
    """
    #pdb.set_trace()
    m = {}
    for op, arg1, arg2 in p:
      if i==len(seq):
            return None
      
      if dis.opmap != ord(seq):
            return None
      if arg1 == '':
            pass
      else:
            if seq == '': return None
            
            a1 = ord(seq)
            if type(arg1) is str:
                m=a1
            elif type(arg1) is int:
                if arg1 != a1: return None
            elif not arg1(a1):
                return None
      #don't need arg2 in this program

      i+=1
      
    return m
      
def int_to_bytecode_arg(i):
    return chr(i% 256) +\
         chr(i // 256)
def patch(fun):
    NOP = chr(dis.opmap['NOP'])
    co = fun.func_code
    old = list(decode_bytecode(fun))
    new = [] #a list of characters
   
    #mapping from label to bytecode offset
    label_table={}
    #if a goto(label) is seen but label is not seen
    #record for the number the bytecode offset of the
    #argument for JUMP_ABSOLUTE for later patching
    goto_table={}
    i=0
    #pdb.set_trace()
    while i
页: [1]
查看完整版本: Python programming with goto