在python中怎么实现goto功能 Posted 2023-04-28
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画九九乘法表?