在python中怎么实现goto功能

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在python中怎么实现goto功能相关的知识,希望对你有一定的参考价值。

假如:
#50# S3=...........(一个赋值行为)
#60# for............(这里有个三重循环)

##三重循环结束##

if ((L-1)==0):
L=0
goto 60
··else:
if (S3>S2):
goto 50

我要实现goto的功能,请问在不安装第三方库的前提下如何实现?

1、首先点击输入下方的代码:

from goto import *

@patch

 def f2():

 goto(10)

2、然后输入下方的代码:

 print 'should not see this'

 label(10)

 for i in range(1,99999):

 print i

3、然后在输入下方的代码就完成了:

 if i == 5:

 goto('out')

 label('out')

 f2()

扩展资料:

用法是:

1、from goto import *。注意暂时不支持import goto,

2、对需要使用goto的函数,前面加个@patch

3、用label(x)和goto(x)的形式写label和goto。x可以是数字或字符串。

goto模块的代码如下:

goto.py

参考技术A

1、首先点击输入下方的代码:

from goto import *

@patch

 def f2():

 goto(10)

2、然后输入下方的代码:

 print 'should not see this'

 label(10)

 for i in range(1,99999):

 print i

3、然后在输入下方的代码就完成了:

 if i == 5:

 goto('out')

 label('out')

 f2()

扩展资料:

用法是:

1、from goto import *。注意暂时不支持import goto,

2、对需要使用goto的函数,前面加个@patch

3、用label(x)和goto(x)的形式写label和goto。x可以是数字或字符串。

goto模块的代码如下:

goto.py

参考技术B

一、具体用法

首先安装一个 goto 的包(因为官方是没有 goto 语句的)

pip install goto-statement

具体的语法--注意: 对需要使用goto的函数,前面加个@patch

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

二、原理解析

原理:通过给所有函数修改trace,然后在异常时就会执行设置的函数。

sys.settrace(_trace)

frame = sys._getframe().f_back

while frame:

frame.f_trace = _trace

frame = frame.f_back



扩展资料:

Goto语句与结构化程序设计

goto语句问题的提出直接推动了结构化程序设计(structuredprogramming)的思想和程序设计方法学的诞生和发展。结构化程序设计方法引入了工程思想和结构化思想,使大型软件的开发和编程都得到了极大的改善。

结构化程序设计方法的主要原则可以概括为自顶向下,逐步求精,模块化,限制使用goto语句。

1.自顶向下:程序设计时,应先考虑总体,后考虑细节;先考虑全局目标,后考虑局部目标。不要一开始就过多追求众多的细节,先从最上层总目标开始设计,逐步使问题具体化。

2.逐步求精:对复杂问题,应设计一些子目标作为过渡,逐步细化。

3.模块化:一个复杂问题,肯定是由若干稍简单的问题构成。模块化是把程序要解决的总目标分解为子目标,再进一步分解为具体的小目标,把每一个小目标称为一个模块。

4.限制使用goto语句

结构化程序设计方法的起源来自对goto语句的认识和争论。肯定的结论是,在块和进程的非正常出口处往往需要用goto语句,使用goto语句会使程序执行效率较高;在合成程序目标时,goto语句往往是有用的,如返回语句用goto。

否定的结论是,goto语句是有害的,是造成程序混乱的祸根,程序的质量与goto语句的数量成反比,应该在所有高级程序设计语言中取消goto语句。取消goto语句后,程序易于理解、易于排错、容易维护,容易进行正确性证明。作为争论的结论,1974年Knuth发表了令人信服的总结,并证实了:

(1)goto语句确实有害,应当尽量避免;

(2)完全避免使用goto语句也并非是个明智的方法,有些地方使用goto语句,会使程序流程更清楚、效率更高。

(3)争论的焦点不应该放在是否取消goto语句上,而应该放在用什么样的程序结构上。其中最关键的是,应在以提高程序清晰性为目标的结构化方法中限制使用goto语句

参考资料:

百度百科——goto语句

参考技术C

goto语句也称为无条件转移语句,其一般格式如下: goto 语句标号; 其中语句标号是按标识符规定书写的符号, 放在某一语句行的前面,标号后加冒号(:)。语句标号起标识语句的作用,与goto 语句配合使用。

用法是:

1. from goto import *。注意暂时不支持import goto,不是不能实现,是暂时没时间写。

2.对需要使用goto的函数,前面加个@patch

3.用label(x)和goto(x)的形式写label和goto。x可以是数字或字符串。

 goto模块的代码如下:

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]

        i += 1

        arguments = ""

        if ord(op) >= dis.HAVE_ARGUMENT:

            arguments = c[i : i+2]

            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[ord(op)]

        else:

            print dis.opname[ord(op)] +' '+str(ord(arg[0]))+' '+str(ord(arg[1]))

        

def match_pattern(seq, i, p):

    """

    try to match pattern p to seq[i:], return None if match failed

    seq: output of decode_bytecode

    p -> [instr, instr, ...]

    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[op] != ord(seq[i][0]):

            return None


        if arg1 == '':

            pass

        else:

            if seq[i][1] == '': return None

            

            a1 = ord(seq[i][1][0])

            if type(arg1) is str:

                m[arg1]=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<len(old):

        m= match_pattern(old, i,

                         [('LOAD_GLOBAL','fun_name',''),

                          ('LOAD_CONST','label',''),

                          ('CALL_FUNCTION',1,''),

                          ('POP_TOP','','')])

        if m:

            stmt = co.co_names[m['fun_name']]

            label = co.co_consts[m['label']]

            

        if   m and stmt == 'goto':

            # we have a goto statement

            if label_table.has_key(label):

                arg = int_to_bytecode_arg(label_table[label])

            else:

                arg = '\\xff\\xff'

                goto_table[label] =\\

                 goto_table.get(label, [])+[len(new)+1]

            new += chr(dis.opmap['JUMP_ABSOLUTE'])

            new += arg

            #todo

            #this is to maintain proper bytecode offset to

            #source code line number mapping. A better way

            #would be fixing the mapping instead of using

            #placeholders

            new += NOP*7

            i += 4

        elif m and stmt == 'label':

            # we have a label statement

            label_table[label]=len(new)

            if goto_table.has_key(label):

                for offset in goto_table[label]:

                    new[offset: offset+2]=int_to_bytecode_arg(len(new))

                del goto_table[label]

            new += NOP*10

            i += 4

        else:

            # emit as-is 

            new += old[i][0] #the opcode

            new += old[i][1] #its args if it has 

            i += 1


    if len(goto_table):

        #todo: output line number

        raise Exception('missing label')


    import types

    newcode = types.CodeType(co.co_argcount,

                       co.co_nlocals,

                       co.co_stacksize,

                       co.co_flags,

                       ''.join(new),

                       co.co_consts,

                       co.co_names,

                       co.co_varnames,

                       co.co_filename,

                       co.co_name,

                       co.co_firstlineno,

                       co.co_lnotab)

    return types.FunctionType(newcode,fun.func_globals)

参考技术D 使用如下例:

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

python 一个函数装饰器,它重写字节码,在Python中启用goto。请参阅https://github.com/snoack/python-goto

import dis
import struct
import array
import types
import functools


class _Bytecode:
    def __init__(self):
        code = (lambda: x if x else y).__code__.co_code
        opcode, oparg = struct.unpack_from('BB', code, 2)

        # Starting with Python 3.6, the bytecode format has been changed to use
        # 16-bit words (8-bit opcode + 8-bit argument) for each instruction,
        # as opposed to previously 24-bit (8-bit opcode + 16-bit argument) for
        # instructions that expect an argument or just 8-bit for those that don't.
        # https://bugs.python.org/issue26647
        if dis.opname[opcode] == 'POP_JUMP_IF_FALSE':
            self.argument = struct.Struct('B')
            self.have_argument = 0
            # As of Python 3.6, jump targets are still addressed by their byte
            # unit. This, however, is matter to change, so that jump targets,
            # in the future, will refer to the code unit (address in bytes / 2).
            # https://bugs.python.org/issue26647
            self.jump_unit = 8 // oparg
        else:
            self.argument = struct.Struct('<H')
            self.have_argument = dis.HAVE_ARGUMENT
            self.jump_unit = 1

    @property
    def argument_bits(self):
        return self.argument.size * 8


_BYTECODE = _Bytecode()


def _make_code(code, codestring):
    args = [
        code.co_argcount,  code.co_nlocals,     code.co_stacksize,
        code.co_flags,     codestring,          code.co_consts,
        code.co_names,     code.co_varnames,    code.co_filename,
        code.co_name,      code.co_firstlineno, code.co_lnotab,
        code.co_freevars,  code.co_cellvars
    ]

    try:
        args.insert(1, code.co_kwonlyargcount)  # PY3
    except AttributeError:
        pass

    return types.CodeType(*args)


def _parse_instructions(code):
    extended_arg = 0
    extended_arg_offset = None
    pos = 0

    while pos < len(code):
        offset = pos
        if extended_arg_offset is not None:
            offset = extended_arg_offset

        opcode = struct.unpack_from('B', code, pos)[0]
        pos += 1

        oparg = None
        if opcode >= _BYTECODE.have_argument:
            oparg = extended_arg | _BYTECODE.argument.unpack_from(code, pos)[0]
            pos += _BYTECODE.argument.size

            if opcode == dis.EXTENDED_ARG:
                extended_arg = oparg << _BYTECODE.argument_bits
                extended_arg_offset = offset
                continue

        extended_arg = 0
        extended_arg_offset = None
        yield (dis.opname[opcode], oparg, offset)


def _write_instruction(buf, pos, opname, oparg=0):
    extended_arg = oparg >> _BYTECODE.argument_bits
    if extended_arg != 0:
        pos = _write_instruction(buf, pos, 'EXTENDED_ARG', extended_arg)
        oparg &= (1 << _BYTECODE.argument_bits) - 1

    opcode = dis.opmap[opname]
    buf[pos] = opcode
    pos += 1

    if opcode >= _BYTECODE.have_argument:
        _BYTECODE.argument.pack_into(buf, pos, oparg)
        pos += _BYTECODE.argument.size

    return pos


def _find_labels_and_gotos(code):
    labels = {}
    gotos = []

    block_stack = []
    block_counter = 0

    opname1 = oparg1 = offset1 = None
    opname2 = oparg2 = offset2 = None
    opname3 = oparg3 = offset3 = None

    for opname4, oparg4, offset4 in _parse_instructions(code.co_code):
        if opname1 in ('LOAD_GLOBAL', 'LOAD_NAME'):
            if opname2 == 'LOAD_ATTR' and opname3 == 'POP_TOP':
                name = code.co_names[oparg1]
                if name == 'label':
                    labels[oparg2] = (offset1,
                                      offset4,
                                      tuple(block_stack))
                elif name == 'goto':
                    gotos.append((offset1,
                                  offset4,
                                  oparg2,
                                  tuple(block_stack)))
        elif opname1 in ('SETUP_LOOP',
                         'SETUP_EXCEPT', 'SETUP_FINALLY',
                         'SETUP_WITH', 'SETUP_ASYNC_WITH'):
            block_counter += 1
            block_stack.append(block_counter)
        elif opname1 == 'POP_BLOCK' and block_stack:
            block_stack.pop()

        opname1, oparg1, offset1 = opname2, oparg2, offset2
        opname2, oparg2, offset2 = opname3, oparg3, offset3
        opname3, oparg3, offset3 = opname4, oparg4, offset4

    return labels, gotos


def _inject_nop_sled(buf, pos, end):
    while pos < end:
        pos = _write_instruction(buf, pos, 'NOP')


def _patch_code(code):
    labels, gotos = _find_labels_and_gotos(code)
    buf = array.array('B', code.co_code)

    for pos, end, _ in labels.values():
        _inject_nop_sled(buf, pos, end)

    for pos, end, label, origin_stack in gotos:
        try:
            _, target, target_stack = labels[label]
        except KeyError:
            raise SyntaxError('Unknown label {0!r}'.format(code.co_names[label]))

        target_depth = len(target_stack)
        if origin_stack[:target_depth] != target_stack:
            raise SyntaxError('Jump into different block')

        failed = False
        try:
            for i in range(len(origin_stack) - target_depth):
                pos = _write_instruction(buf, pos, 'POP_BLOCK')
            pos = _write_instruction(buf, pos, 'JUMP_ABSOLUTE', target // _BYTECODE.jump_unit)
        except (IndexError, struct.error):
            failed = True

        if failed or pos > end:
            raise SyntaxError('Jump out of too many nested blocks')

        _inject_nop_sled(buf, pos, end)

    return _make_code(code, buf.tostring())


def with_goto(func_or_code):
    if isinstance(func_or_code, types.CodeType):
        return _patch_code(func_or_code)

    return functools.update_wrapper(
        types.FunctionType(
            _patch_code(func_or_code.__code__),
            func_or_code.__globals__,
            func_or_code.__name__,
            func_or_code.__defaults__,
            func_or_code.__closure__,
        ),
        func_or_code
    )
import sys
import pytest
from goto import with_goto

CODE = '''\
i = 0
result = []
label .start
if i == 10:
    goto .end
result.append(i)
i += 1
goto .start
label .end
'''

EXPECTED = list(range(10))


def test_range_as_code():
    ns = {}
    exec(with_goto(compile(CODE, '', 'exec')), ns)
    assert ns['result'] == EXPECTED


def make_function(code):
    lines = ['def func():']
    for line in code:
        lines.append('    ' + line)
    lines.append('    return result')

    ns = {}
    exec('\n'.join(lines), ns)
    return ns['func']


def test_range_as_function():
    assert with_goto(make_function(CODE.splitlines()))() == EXPECTED


def test_EXTENDED_ARG():
    code = []
    for i in range(2**16):
        code.append('label .l{0}'.format(i))
    code.append('result = True')
    code.append('goto .foo')
    code.append('result = "dead code"')
    code.append('label .foo')
    assert with_goto(make_function(code))() is True


def test_jump_out_of_loop():
    @with_goto
    def func():
        for i in range(10):
            goto .end
        label .end
        return i

    assert func() == 0


def test_jump_into_loop():
    def func():
        for i in range(10):
            label .loop
        goto .loop

    pytest.raises(SyntaxError, with_goto, func)

if sys.version_info >= (3, 6):
    def test_jump_out_of_nested_2_loops():
        @with_goto
        def func():
            for i in range(2):
                for j in range(2):
                    goto .end
            label .end
            return (i, j)

        assert func() == (0, 0)

    def test_jump_out_of_nested_3_loops():
        def func():
            for i in range(2):
                for j in range(2):
                    for k in range(2):
                        goto .end
            label .end
            return (i, j, k)

        pytest.raises(SyntaxError, with_goto, func)
else:
    def test_jump_out_of_nested_4_loops():
        @with_goto
        def func():
            for i in range(2):
                for j in range(2):
                    for k in range(2):
                        for m in range(2):
                            goto .end
            label .end
            return (i, j, k, m)

        assert func() == (0, 0, 0, 0)

    def test_jump_out_of_nested_5_loops():
        def func():
            for i in range(2):
                for j in range(2):
                    for k in range(2):
                        for m in range(2):
                            for n in range(2):
                                goto .end
            label .end
            return (i, j, k, m, n)

        pytest.raises(SyntaxError, with_goto, func)


def test_jump_across_loops():
    def func():
        for i in range(10):
            goto .other_loop

        for i in range(10):
            label .other_loop

    pytest.raises(SyntaxError, with_goto, func)


def test_jump_out_of_try_block():
    @with_goto
    def func():
        try:
            rv = None
            goto .end
        except:
            rv = 'except'
        finally:
            rv = 'finally'
        label .end
        return rv

    assert func() == None


def test_jump_into_try_block():
    def func():
        try:
            label .block
        except:
            pass
        goto .block

    pytest.raises(SyntaxError, with_goto, func)


def test_jump_to_unknown_label():
    def func():
        goto .unknown

    pytest.raises(SyntaxError, with_goto, func)


def test_function_is_copy():
    def func():
        pass

    func.foo = 'bar'
    newfunc = with_goto(func)

    assert newfunc is not func
    assert newfunc.foo == 'bar'

以上是关于在python中怎么实现goto功能的主要内容,如果未能解决你的问题,请参考以下文章

python 一个函数装饰器,它重写字节码,在Python中启用goto。请参阅https://github.com/snoack/python-goto

python 怎么画爱心?如何在Python里面画爱心啊?求解

python turtle画图怎么连接两点

怎么看写的python代码的功能模块的核心功能

武汉加油!(Python版)

怎么用python中turtle画九九乘法表?