def main(): filename = sys.argv[1] fptr = open(filename, "r") source = fptr.read() fptr.seek(0) source_lines = format_source_lines(fptr.readlines()) fptr.close() draw_header("Source") display_source(source_lines) code = compile(source, filename, "exec") vm = BytecodeVM(code, source_lines, filename) WITH_DEBUGGER = False if not WITH_DEBUGGER: draw_header("Disassembly") dis.dis(code) # Configure the VM and set the settings based on command line. For now use defaults config = configure_vm() config.show_disassembly = True vm.config = config vm.execute() else: debugger = Debugger(code, source_lines, filename) debugger.execute(False)
def get_disassembly(self, func, lasti=-1, wrapper=True): output = io.StringIO() if wrapper: dis.dis(func, file=output) else: dis.disassemble(func, lasti, file=output) return output.getvalue()
def verbose(p, func, env): if not debug_print(func, env): return pipeline.apply_transform(p, func, env) title = "%s [ %s %s(%s) ]" % (_passname(p), func.type.restype, _funcname(func), ", ".join(map(str, func.type.argtypes))) print(title.center(60).center(90, "-")) if isinstance(func, types.FunctionType): dis.dis(func) func, env = pipeline.apply_transform(p, func, env) print() print(func) return func, env before = _formatfunc(func) func, env = pipeline.apply_transform(p, func, env) after = _formatfunc(func) if before != after: print(pykit.ir.diff(before, after)) return func, env
def dump(co, indent=0): import dis import types def pprint(text, extra=0): for i in range(indent + extra): print(" ", end="") print(text) pprint("co_name:\t{0}".format(co.co_name)) for key in dir(co): if not key.startswith("co_"): continue if key in ["co_name", "co_code", "co_lnotab"]: continue elif key == "co_consts": pprint("{0}:".format(key)) for v in co.co_consts: if type(v) == types.CodeType: pprint("- Code Object:") dump(v, indent + 1) else: pprint("- {0}".format(v)) elif key == "co_flags": val = dis.pretty_flags(co.co_flags) pprint("{0}:\t\t{1}".format(key, val)) else: val = getattr(co, key) pprint("{0}:\t{1}".format(key, val)) # doesn't obey indent level dis.dis(co)
def disassemble_pyc(path): with open(path, "rb") as file_: bytecode = file_.read() stringio = io.StringIO() dis.dis(bytecode, file=stringio) stringio.seek(0) return Status.normal, fill3.Text(stringio.read())
def d(text, mode='exec', file=None): """ Interactive convenience for displaying the disassembly of a code string. Compiles `text` and recursively traverses the result looking for `code` objects to render with `dis.dis`. Parameters ---------- text : str Text of Python code to compile and disassemble. mode : {'exec', 'eval'}, optional Mode for `compile`. Default is 'exec'. file : None or file-like object, optional File to use to print output. If the default of `None` is passed, we use sys.stdout. """ if file is None: file = sys.stdout for name, co in walk_code(compile(text, '<show>', mode)): print(name, file=file) print('-' * len(name), file=file) dis.dis(co, file=file) print('', file=file)
def _disassemble(code): """Disassemble a code object.""" sio = StringIO() findlinestarts = dis.findlinestarts dis.findlinestarts = lambda _: {} findlabels = dis.findlabels dis.findlabels = lambda _: {} sys.stdout, sio = sio, sys.stdout try: dis.dis(code) finally: sys.stdout, sio = sio, sys.stdout dis.findlinestarts = findlinestarts dis.findlabels = findlabels disassembled_code = [ re.sub('<code object .* line [0-9]+>', '<code object>', sio.getvalue())] for c in code.co_consts: if hasattr(c, 'co_code'): disassembled_code += _disassemble(c) return disassembled_code
def compile_func(arg_names, statements, name='_the_func', debug=False): """Compile a list of statements as the body of a function and return the resulting Python function. If `debug`, then print out the bytecode of the compiled function. """ arguments = ast.arguments( args=[_to_arg(n) for n in arg_names], defaults=[ex_literal(None) for _ in arg_names], kwonlyargs=[], kw_defaults=[] ) func_def = ast.FunctionDef( name=name, args=arguments, body=statements, decorator_list=[] ) mod = ast.Module([func_def]) ast.fix_missing_locations(mod) prog = compile(mod, '<generated>', 'exec') # Debug: show bytecode. if debug: dis.dis(prog) for const in prog.co_consts: if isinstance(const, types.CodeType): dis.dis(const) the_locals = {} exec(prog, {}, the_locals) return the_locals[name]
def compile_func(arg_names, statements, name='_the_func', debug=False): """Compile a list of statements as the body of a function and return the resulting Python function. If `debug`, then print out the bytecode of the compiled function. """ func_def = ast.FunctionDef( name, ast.arguments( [ast.Name(n, ast.Param()) for n in arg_names], None, None, [ex_literal(None) for _ in arg_names], ), statements, [], ) mod = ast.Module([func_def]) ast.fix_missing_locations(mod) prog = compile(mod, '<generated>', 'exec') # Debug: show bytecode. if debug: dis.dis(prog) for const in prog.co_consts: if isinstance(const, types.CodeType): dis.dis(const) the_locals = {} exec prog in {}, the_locals return the_locals[name]
def cont(ni): try: if ni == Sandbox.SUSPEND_TIME: ni = g.send(0.1) elif ni == Sandbox.SUSPEND_INST: ni = g.send(10000) else: callback(formatter.getReport()) return if exc.counter > 1000000: raise TimeoutError("Report has exceeded 1,000,000 instructions") except: import traceback a_report.log('ERROR', traceback.format_exc().replace('\n', '<br/>')) s_exc = exc while s_exc.sub: a_report.log('ERROR', 'stackPointer: %i' % s_exc.index) debug = io.StringIO() dis.dis(s_exc.function.code, file=debug) a_report.log('CODE<br/>', debug.getvalue().replace('\n', '<br/>')) s_exc = s_exc.sub a_report.log('ERROR', 'stackPointer: %i' % s_exc.index) debug = io.StringIO() dis.dis(s_exc.function.code, file=debug) a_report.log('CODE<br/>', debug.getvalue().replace('\n', '<br/>')) raise reactor.callLater(0.0001, cont, ni)
def testexec0(): y=1 #STORE_FAST exec("y=2") assert y==2 #LOAD_FAST cod=compile("y=3",'<string>','exec') dis.dis(cod) #STORE_NAME print cod.co_names exec(cod) in globals(), locals() assert y==2 #LOAD_FAST exec("y=4")in globals(), locals() assert y==2 #LOAD_FAST '''查询locals()函数的说明: The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter. ''' ddd=copy.copy(locals()) exec("y=4")in globals(), ddd assert ddd['y']==4 assert y==2 '''而这也果然就可以了''' exec("z=1") assert z==1 #LOAD_NAME '''定义一个新变量,可以,因为这个是freeval,只能用LOAD_NAME''' exec("q=1") in globals(),locals() assert q==1 #LOAD_NAME '''定义一个新变量,可以'''
def test(func, *argslist): # send answers to JSON and back to get them into a standard form. answers = json.loads(json.dumps([func(*args) for args in argslist])) label = func.__name__ + (": " + func.__doc__ if func.__doc__ else "") try: jscode = tropyc.transform_js(func, debug=True) tempfd, tempname = tempfile.mkstemp(prefix="tropyc", suffix=".js") os.write(tempfd, jscode) callfunc = ",".join(["$P%s(%s)" % (func.__name__, json.dumps(args)[1:-1]) for args in argslist]) os.write(tempfd, "\nprint(JSON.stringify([%s]));\n" % callfunc) os.close(tempfd) rhino_file = os.popen("rhino -f libjs/json2.js -f libjs/library.js -f %s" % tempname) results = json.load(rhino_file) rhino_file.close() os.unlink(tempname) if answers == results: print "%-40s PASS" % label return else: print "%-40s FAIL" % label pprint.pprint(answers) pprint.pprint(results) print jscode except Exception, e: print "%-40s EXCEPTION %s" % (label, e) dis.dis(func)
def main(): multiply() for r in z: print r print "Dissasembler" print dis.dis(multiply)
def main(): import argparse parser = argparse.ArgumentParser( description='Tyrian is a lisp to python bytecode compiler') parser.add_argument( 'input_filename', type=str, help="input filename containing LISP") parser.add_argument( 'output_filename', type=str, help="file to write bytecode to") parser.add_argument( '-v', '--verbose', action='count', default=0, help="controls verbosity. Must be used a few times to lower the \ barrier to the interesting stuff") args = parser.parse_args() verbosity = 5 - args.verbose assert verbosity in range(0, 6), 'Bad verbosity' logger.setLevel(_verbosity_map[verbosity][0]) inst = Tyrian() bytecode = inst.compile(args.input_filename) if _verbosity_map[verbosity][0] <= logging.INFO: dis(bytecode.code()) logger.info('Writing to file...') with open(args.output_filename, 'wb') as fh: inst.compiler.write_code_to_file( bytecode.code(), fh, args.input_filename)
def d(obj, mode='exec', file=None): """ Interactive convenience for displaying the disassembly of a function, module, or code string. Compiles `text` and recursively traverses the result looking for `code` objects to render with `dis.dis`. Parameters ---------- obj : str, CodeType, or object with __code__ attribute Object to disassemble. If `obj` is an instance of CodeType, we use it unchanged. If `obj` is a string, we compile it with `mode` and then disassemble. Otherwise, we look for a `__code__` attribute on `obj`. mode : {'exec', 'eval'}, optional Mode for `compile`. Default is 'exec'. file : None or file-like object, optional File to use to print output. If the default of `None` is passed, we use sys.stdout. """ if file is None: file = sys.stdout for name, co in walk_code(extract_code(obj, compile_mode=mode)): print(name, file=file) print('-' * len(name), file=file) dis.dis(co, file=file) print('', file=file)
def test(): import sys if sys.version[:3] > '2.4': outmost_iterable_name = '.0' else: outmost_iterable_name = '[outmost-iterable]' import dis for line in test_lines.split('\n'): if not line or line.isspace(): continue line = line.strip() if line.startswith('#'): continue code = compile(line, '<?>', 'eval').co_consts[0] ast1 = parse(line).node.nodes[0].expr ast1.code.quals[0].iter.name = outmost_iterable_name try: ast2 = Decompiler(code).ast except Exception as e: print() print(line) print() print(ast1) print() dis.dis(code) raise if str(ast1) != str(ast2): print() print(line) print() print(ast1) print() print(ast2) print() dis.dis(code) break else: print('OK: %s' % line) else: print('Done!')
def test_purefunction_promote_args(self): @purefunction_promote(promote_args='0') def g(func, x): return func + 1 def f(x): return g(x * 2, x) import dis from StringIO import StringIO import sys s = StringIO() prev = sys.stdout sys.stdout = s try: dis.dis(g) finally: sys.stdout = prev x = s.getvalue().find('CALL_FUNCTION') assert x != -1 x = s.getvalue().find('CALL_FUNCTION', x) assert x != -1 x = s.getvalue().find('CALL_FUNCTION', x) assert x != -1 res = self.interpret(f, [2]) assert res == 5
def test_count_thresh(): import ast import inspect p = ast.parse(inspect.getsource(count_thresh_orig)) print "AST" print ast.dump(p) print "Bytecode" import dis dis.dis(count_thresh_orig) v = np.array([1.2, 1.4, 5.0, 2, 3]) parakeet_result = count_thresh(v, 2.0) python_result = count_thresh_orig(v, 2.0) assert parakeet_result == python_result, "Parakeet %s != Python %s" % (parakeet_result, python_result) v = np.random.randn(10 ** 4) py_start = time.time() count_thresh_orig(v, 2.0) py_time = time.time() - py_start np_start = time.time() np_thresh(v, 2.0) np_time = time.time() - np_start par_start = time.time() count_thresh(v, 2.0) par_time = time.time() - par_start print "Python time: %.5f" % py_time print "NumPy time: %.5f" % np_time print "Parakeet time: %.5f" % par_time
def find_method_dependencies(method): buffer = cStringIO.StringIO() stdout = sys.stdout sys.stdout = buffer dis(method) bytecodes = [x.split() for x in buffer.getvalue().split("\n")] sys.stdout = stdout buffer.close() sets = Set() requires = Set() self = 0 for bytecode in bytecodes: if len(bytecode) > 3: if self: if bytecode[1] == "STORE_ATTR": sets.append(bytecode[3][1:-1]) elif bytecode[1] == "LOAD_ATTR": requires.append(bytecode[3][1:-1]) self = 0 elif (len(bytecode) > 3 and bytecode[1] == "LOAD_FAST" and bytecode[2] == "0"): self = 1 requires = filter(lambda x: x not in sets, requires) if sets == [] and requires == []: print ("WARNING: %s appears to have no side effects." "What are you, some kind of functional programmer? ;)" % method.__name__) return sets, requires
def test_elidable_promote_args(self): @elidable_promote(promote_args="0") def g(func, x): return func + 1 def f(x): return g(x * 2, x) import dis from StringIO import StringIO import sys s = StringIO() prev = sys.stdout sys.stdout = s try: dis.dis(g) finally: sys.stdout = prev x = s.getvalue().find("CALL_FUNCTION") assert x != -1 x = s.getvalue().find("CALL_FUNCTION", x) assert x != -1 x = s.getvalue().find("CALL_FUNCTION", x) assert x != -1 res = self.interpret(f, [2]) assert res == 5
def dis_code(code): for const in code.co_consts: if isinstance(const, types.CodeType): dis_code(const) print("") print(code) dis.dis(code)
def disasm(code): hold = sys.stdout try: sys.stdout = cStringIO.StringIO() dis.dis(code) return sys.stdout.getvalue() finally: sys.stdout = hold
def diss(code): codepp(code) if loud: dis.dis(code) for c in code.co_consts: if isinstance(c, types.CodeType): report() report('------', c, '------') diss(c)
def walk(co, match=None): if match is None or co.co_name == match: dump(co) print dis.dis(co) for obj in co.co_consts: if type(obj) == types.CodeType: walk(obj, match)
def debug(self): compiler = Compiler() for (instruction, args) in self.parse(): print(instruction, args) compiler.compile(instruction, args) code = compiler.build() import dis dis.dis(code)
def dis_code(code): """Disassemble `code` and all the code it refers to.""" for const in code.co_consts: if isinstance(const, types.CodeType): dis_code(const) print("") print(code) dis.dis(code)
def disassemble(func): f = StringIO() tmp = sys.stdout sys.stdout = f dis.dis(func) sys.stdout = tmp result = f.getvalue() f.close() return result
def get_disassembly(self, func, lasti=-1, wrapper=True): # We want to test the default printing behaviour, not the file arg output = io.StringIO() with contextlib.redirect_stdout(output): if wrapper: dis.dis(func) else: dis.disassemble(func, lasti) return output.getvalue()
def print_co(co): print 'name:', co.co_name, '----------------------------------------' print 'consts:', co.co_consts print 'names:', co.co_names print 'varnames:', co.co_varnames print 'freevars:', co.co_freevars print 'cellvars:', co.co_cellvars print 'lnotab:' print dis.dis(co)
def _getmyre0 (self): mython_module_path = os.path.join(os.path.split(__file__)[0], "test_regex01.my") module_co, _ = toplevel_compile(mython_module_path) if __debug__: dis.dis(module_co) exec module_co return myre0
class Sentence: def __init__(self, text): self.text = text self.words = RE_WORD.findall(text) def __repr__(self): return 'Sentence(%s)' % reprlib.repr(self.text) def __iter__(self): for word in self.words: yield word return def iter2(self): for word in self.words: yield word s1 = Sentence("Time to master yield") i1 = iter(s1) print("__iter__ with the return\n") print(dis(s1.__iter__)) print("2 NO return\n") print(dis(s1.iter2)) # import pdb; pdb.set_trace()
def magic_calculation(a, b): result = 0 for i in range(1, 3): try: if i > a: raise Exception('Too far') else: result = result + (a**b) / i except: result = b + a break return result if __name__ == '__main__': import dis dis.dis(magic_calculation)
from inspect import CO_VARKEYWORDS def foo(a, (b,), (c, d), (e, (f, g), h)): print(a, b, c, d, e, f, g , h) if __name__ == "__main__": foo(1, (2, ), (3, 4), (5, (6, 7), 8)) import dis dis.dis(foo)
import dis def procedure(): print('hello') dis.dis(procedure) ## 0 SET_LINENO 3 ## ## 3 SET_LINENO 4 ## 6 LOAD_CONST 1 ('hello') ## 9 PRINT_ITEM ## 10 PRINT_NEWLINE ## 11 LOAD_CONST 0 (None) ## 14 RETURN_VALUE
def f2(): nonlocal count count += 1 return count return f2 if __name__ == '__main__': avg = Averager() print(avg(10)) print(avg(11)) print(avg(12), '\n') avg2 = get_averager() print(avg2.__code__.co_varnames) #('new_value', 'total') print(avg2.__code__.co_freevars) #('series',) print(avg2(10)) print(avg2(11)) print(avg2(12)) print(avg2.__closure__[0].cell_contents) f = f1() print(f()) print(f()) print(f()) import dis print(dis.dis(f))
def update_event(self, inp=-1): self.set_output_val(0, dis.dis(self.input(0)))
def rawthunk(arg): print 'called thunk with', arg def rawclasstest(): class foo: x = 1 f = foo() def dostuff(self): ## n = 7 ## thunk(1) ## classtest() ## if n: ## print 'hi' ## else: ## print 'bye' class foo: x = 1 f = foo() return 1 dis.dis(dostuff) c = Code(dostuff.func_code) i = Interpreter(c, {}, { 'thunk': safe(rawthunk, {}), 'classtest': safe(rawclasstest, {}) }) print i.run().value
def func1(n, x): if n % x == 0: print('equal') def func2(n, x): if not n % x: print('equal') import dis dis.dis(func1) dis.dis(func2) # https://docs.python.org/3.7/library/dis.html
print('\033c') print("\t\033[36;1;6;4;5mFriday Friday Friday!\033[0m\n") from dis import dis import opcode # x = [x for x in range(2)] # TypeError: don't know how to disassemble list objects y = (x for x in range(2)) print("\n\ny = (x for x in range(2))\n\n") print(dis(y)) # print(dis(y))
# Attempt to make the Quarter Number Sequence from Fib #example on Python site, used Sage code on #https://oeis.org/search?q=0%2C1%2C2%2C4%2C6%2C9%2C12&sort=&language=english&go=Search #went back to Fib code and finished in about ten minutes import dis def quar(n): a, b = 0, 1 #we explicitly define the first two inputs while a < n: print(a, end=' ') #prints all a vaues until loop terminates at input n a, b = a + b, a//b + 1 #the function is defined to replace a, b after first adding the terms, then taking #the integer floor of the quotient a/b and adding 1, then storing these two new values into a, b and repeating print() quar(1000) dis.dis(quar) # i added dis in an attempt to understand what was going on at the machine level to understand the loop # after reading about psuedocode in Cox, O'Shea, Neil I figured out how simple it really was. The magic is in the a, b structure #originaly, this was the add the right, down, left, up squares #below is a visualization of the loop #0, 1 := 1, 1 #1, 1 := 2, 2 #2, 2 := 4, 1 #4, 2 := 6, 3 #6, 3 := 9, 3 #9, 3 := 12, 4 #12, 4 := 16, 4 #...
def infer_return_type_func(f, input_types, debug=False, depth=0): """Analyses a function to deduce its return type. Args: f: A Python function object to infer the return type of. input_types: A sequence of inputs corresponding to the input types. debug: Whether to print verbose debugging information. depth: Maximum inspection depth during type inference. Returns: A TypeConstraint that that the return value of this function will (likely) satisfy given the specified inputs. Raises: TypeInferenceError: if no type can be inferred. """ if debug: print() print(f, id(f), input_types) dis.dis(f) from . import opcodes simple_ops = dict((k.upper(), v) for k, v in opcodes.__dict__.items()) co = f.__code__ code = co.co_code end = len(code) pc = 0 free = None yields = set() returns = set() # TODO(robertwb): Default args via inspect module. local_vars = list(input_types) + [typehints.Union[ ()]] * (len(co.co_varnames) - len(input_types)) state = FrameState(f, local_vars) states = collections.defaultdict(lambda: None) jumps = collections.defaultdict(int) # In Python 3, use dis library functions to disassemble bytecode and handle # EXTENDED_ARGs. ofs_table = {} # offset -> instruction for instruction in dis.get_instructions(f): ofs_table[instruction.offset] = instruction # Python 3.6+: 1 byte opcode + 1 byte arg (2 bytes, arg may be ignored). inst_size = 2 opt_arg_size = 0 last_pc = -1 while pc < end: # pylint: disable=too-many-nested-blocks start = pc instruction = ofs_table[pc] op = instruction.opcode if debug: print('-->' if pc == last_pc else ' ', end=' ') print(repr(pc).rjust(4), end=' ') print(dis.opname[op].ljust(20), end=' ') pc += inst_size if op >= dis.HAVE_ARGUMENT: arg = instruction.arg pc += opt_arg_size if debug: print(str(arg).rjust(5), end=' ') if op in dis.hasconst: print('(' + repr(co.co_consts[arg]) + ')', end=' ') elif op in dis.hasname: print('(' + co.co_names[arg] + ')', end=' ') elif op in dis.hasjrel: print('(to ' + repr(pc + arg) + ')', end=' ') elif op in dis.haslocal: print('(' + co.co_varnames[arg] + ')', end=' ') elif op in dis.hascompare: print('(' + dis.cmp_op[arg] + ')', end=' ') elif op in dis.hasfree: if free is None: free = co.co_cellvars + co.co_freevars print('(' + free[arg] + ')', end=' ') # Actually emulate the op. if state is None and states[start] is None: # No control reaches here (yet). if debug: print() continue state |= states[start] opname = dis.opname[op] jmp = jmp_state = None if opname.startswith('CALL_FUNCTION'): if opname == 'CALL_FUNCTION': pop_count = arg + 1 if depth <= 0: return_type = Any elif isinstance(state.stack[-pop_count], Const): return_type = infer_return_type( state.stack[-pop_count].value, state.stack[1 - pop_count:], debug=debug, depth=depth - 1) else: return_type = Any elif opname == 'CALL_FUNCTION_KW': # TODO(udim): Handle keyword arguments. Requires passing them by name # to infer_return_type. pop_count = arg + 2 if isinstance(state.stack[-pop_count], Const): from apache_beam.pvalue import Row if state.stack[-pop_count].value == Row: fields = state.stack[-1].value return_type = row_type.RowTypeConstraint( zip( fields, Const.unwrap_all(state.stack[-pop_count + 1:-1]))) else: return_type = Any else: return_type = Any elif opname == 'CALL_FUNCTION_EX': # stack[-has_kwargs]: Map of keyword args. # stack[-1 - has_kwargs]: Iterable of positional args. # stack[-2 - has_kwargs]: Function to call. has_kwargs = arg & 1 # type: int pop_count = has_kwargs + 2 if has_kwargs: # TODO(udim): Unimplemented. Requires same functionality as a # CALL_FUNCTION_KW implementation. return_type = Any else: args = state.stack[-1] _callable = state.stack[-2] if isinstance(args, typehints.ListConstraint): # Case where there's a single var_arg argument. args = [args] elif isinstance(args, typehints.TupleConstraint): args = list(args._inner_types()) elif isinstance(args, typehints.SequenceTypeConstraint): args = [element_type(args)] * len( inspect.getfullargspec(_callable.value).args) return_type = infer_return_type(_callable.value, args, debug=debug, depth=depth - 1) else: raise TypeInferenceError('unable to handle %s' % opname) state.stack[-pop_count:] = [return_type] elif opname == 'CALL_METHOD': pop_count = 1 + arg # LOAD_METHOD will return a non-Const (Any) if loading from an Any. if isinstance(state.stack[-pop_count], Const) and depth > 0: return_type = infer_return_type(state.stack[-pop_count].value, state.stack[1 - pop_count:], debug=debug, depth=depth - 1) else: return_type = typehints.Any state.stack[-pop_count:] = [return_type] elif opname in simple_ops: if debug: print("Executing simple op " + opname) simple_ops[opname](state, arg) elif opname == 'RETURN_VALUE': returns.add(state.stack[-1]) state = None elif opname == 'YIELD_VALUE': yields.add(state.stack[-1]) elif opname == 'JUMP_FORWARD': jmp = pc + arg jmp_state = state state = None elif opname == 'JUMP_ABSOLUTE': jmp = arg jmp_state = state state = None elif opname in ('POP_JUMP_IF_TRUE', 'POP_JUMP_IF_FALSE'): state.stack.pop() jmp = arg jmp_state = state.copy() elif opname in ('JUMP_IF_TRUE_OR_POP', 'JUMP_IF_FALSE_OR_POP'): jmp = arg jmp_state = state.copy() state.stack.pop() elif opname == 'FOR_ITER': jmp = pc + arg jmp_state = state.copy() jmp_state.stack.pop() state.stack.append(element_type(state.stack[-1])) else: raise TypeInferenceError('unable to handle %s' % opname) if jmp is not None: # TODO(robertwb): Is this guaranteed to converge? new_state = states[jmp] | jmp_state if jmp < pc and new_state != states[jmp] and jumps[pc] < 5: jumps[pc] += 1 pc = jmp states[jmp] = new_state if debug: print() print(state) pprint.pprint(dict(item for item in states.items() if item[1])) if yields: result = typehints.Iterable[reduce(union, Const.unwrap_all(yields))] else: result = reduce(union, Const.unwrap_all(returns)) finalize_hints(result) if debug: print(f, id(f), input_types, '->', result) return result
#!/usr/bin/env python3 import dis def test(number): return (str(number) + str(number)) def newFunc(string): print("Hello", string) # This will display the disassembly of test(): dis.dis(test) #* 2 0 LOAD_GLOBAL 0 (str) #* 2 LOAD_FAST 0 (number) #* 4 CALL_FUNCTION 1 #* 6 LOAD_GLOBAL 0 (str) #* 8 LOAD_FAST 0 (number) #* 10 CALL_FUNCTION 1 #* 12 BINARY_ADD #* 14 RETURN_VALUE # This will display the disassembly of newFunc() dis.dis(newFunc) #* 2 0 LOAD_GLOBAL 0 (print) #* 2 LOAD_CONST 1 ('Hello') #* 4 LOAD_FAST 0 (string) #* 6 CALL_FUNCTION 2 #* 8 POP_TOP
# tuples are immutable (tuples are lists which cant be edited) list = [10, 'liverpool', 99] tup = (10, 'liverpool', 20) list[1] = 11 #tup[1] = 11 # fail #tup(1) = 11 #fail print(list) from dis import dis #Tuples can be constant folded #Tuples of constants can be precomputed by Python's peephole optimizer or AST-optimizer. Lists, on the other hand, get built-up from scratch: dis(compile("(10, 'abc')", '', 'eval')) dis(compile("[10, 'abc']", '', 'eval')) #Tuples do not need to be copied #Running tuple(some_tuple) returns immediately itself. Since tuples are immutable, they do not have to be copied: #Tuples do not over-allocate #Since a tuple's size is fixed, it can be stored more compactly than lists which need to over-allocate to make append() operations efficient. #This gives tuples a nice space advantage: # This over-allocates proportional to the list size, making room # for additional growth. The over-allocation is mild, but is # enough to give linear-time amortized behavior over a long
def tco(func): code = func.__orig_code__ = func.__code__ while code != (code := single_pass_tco(code)): pass func.__code__ = code return func #*-- TESTING --*# @tco def fact(n, acc=1): if (n < 2): return acc return fact(n - 1, n * acc) dis.dis(fact) def fib(n=1000, a=0, b=1): if n == 0: return a if n == 1: return b return fib(n - 1, b, a + b); import timeit import sys sys.setrecursionlimit(2000) print(timeit.timeit(fib, number=10000)) print(timeit.timeit(tco(fib), number=10000))
#!/usr/bin/python3 import dis class MagicClass: """class Square with a private attribute called size""" def __init__(self, radius=0): if (type(radius) is not int) or type(radius) is not float: raise TypeError('radius must be a number') return self.radius print(dis.dis(MagicClass))
from dis import dis s = 'for i in range(0, 10): print(i)' #compile(source, filename, mode[, flags[, dont_inherit]]) ''' @source字符串或者AST(Abstract Syntax Trees)对象。。 @filename代码文件名称,如果不是从文件读取代码则传递一些可辨认的值。 @mode指定编译代码的种类。可以指定为 exec, eval, single。 @flags变量作用域,局部命名空间,如果被提供,可以是任何映射对象。。 @flags和dont_inherit是用来控制编译源码时的标志 ''' co = compile(s, '', 'exec') #编译python字符串或者文件为字节码 print(dir(co)) print(co.co_code) print(co.co_names) dis(co.co_code) #有点像反编译的效果
def g(w): yield w * 2 yield w ** 2 yield w + 2 gi = g(100) print(f'{next(gi) = }') print(f'{gi.gi_frame.f_lasti = }') print(f'{next(gi) = }') print(f'{gi.gi_frame.f_lasti = }') print(f'{next(gi) = }') print(f'{gi.gi_frame.f_lasti = }') from dis import dis dis(g) # generator is an iterable # generator instance is an iterator # - the underlying computation (i.e., reference to the iterable) # - some state (i.e., where you left off, i.e., the last instruction that you computed) xs = [1, 2, 3, 4] xi = iter(xs) print(f'{next(xi) = }') print(f'{next(xi) = }') print(f'{next(xi) = }') print(f'{next(xi) = }') xs.append(5) print(f'{next(xi) = }') xs.extend([6,7,8])
''' Created on Oct 23, 2014 @author: khiemtd ''' #!/usr/bin/python import dis def sum(): vara = 10 varb = 20 sum = vara + varb print "vara + varb = %d" % sum # Call dis function for the function. dis.dis(sum) import pdb import temp pdb.run('temp') #or python -m pdb myscript.py
#!/usr/bin/env python # encoding: utf-8 import dis class MyObject: """Example for dis.""" CLASS_ATTRIBUTE = 'some value' def __str__(self): return 'MyObject({})'.format(self.name) def __init__(self, name): self.name = name dis.dis(MyObject)
# In [11]: t[2] += [50, 60] # --------------------------------------------------------------------------- # TypeError Traceback (most recent call last) # <ipython-input-11-d877fb0e9d36> in <module> # ----> 1 t[2] += [50, 60] # TypeError: 'tuple' object does not support item assignment # In [12]: t # Out[12]: (1, 2, [30, 40, 50, 60]) # 这里的t虽然抛出异常,但依旧被改动 # 这里虽然可以改成t[2].extend([50,60]), # 但为了说明问题,用代码分析模块dis以下例子: import dis print(dis.dis('s[a] += b')) # 1 0 LOAD_NAME 0 (s) # 2 LOAD_NAME 1 (a) # 4 DUP_TOP_TWO # 6 BINARY_SUBSCR # 8 LOAD_NAME 2 (b) # 10 INPLACE_ADD # 12 ROT_THREE # 14 STORE_SUBSCR # 16 LOAD_CONST 0 (None) # 18 RETURN_VALUE # None # 到14 STORE_SUBSCR时,因为s是不可变元组,所以返回None # 2.7 列表的就地排序sorted, list.sort fruits = ['grape', 'apple', 'banana','orange']
def infer_return_type_func(f, input_types, debug=False, depth=0): """Analyses a function to deduce its return type. Args: f: A Python function object to infer the return type of. input_types: A sequence of inputs corresponding to the input types. debug: Whether to print verbose debugging information. depth: Maximum inspection depth during type inference. Returns: A TypeConstraint that that the return value of this function will (likely) satisfy given the specified inputs. Raises: TypeInferenceError: if no type can be inferred. """ if debug: print() print(f, id(f), input_types) dis.dis(f) from . import opcodes simple_ops = dict((k.upper(), v) for k, v in opcodes.__dict__.items()) co = f.__code__ code = co.co_code end = len(code) pc = 0 extended_arg = 0 # Python 2 only. free = None yields = set() returns = set() # TODO(robertwb): Default args via inspect module. local_vars = list(input_types) + [typehints.Union[()]] * (len(co.co_varnames) - len(input_types)) state = FrameState(f, local_vars) states = collections.defaultdict(lambda: None) jumps = collections.defaultdict(int) # In Python 3, use dis library functions to disassemble bytecode and handle # EXTENDED_ARGs. is_py3 = sys.version_info[0] == 3 if is_py3: ofs_table = {} # offset -> instruction for instruction in dis.get_instructions(f): ofs_table[instruction.offset] = instruction # Python 2 - 3.5: 1 byte opcode + optional 2 byte arg (1 or 3 bytes). # Python 3.6+: 1 byte opcode + 1 byte arg (2 bytes, arg may be ignored). if sys.version_info >= (3, 6): inst_size = 2 opt_arg_size = 0 else: inst_size = 1 opt_arg_size = 2 last_pc = -1 while pc < end: start = pc if is_py3: instruction = ofs_table[pc] op = instruction.opcode else: op = ord(code[pc]) if debug: print('-->' if pc == last_pc else ' ', end=' ') print(repr(pc).rjust(4), end=' ') print(dis.opname[op].ljust(20), end=' ') pc += inst_size if op >= dis.HAVE_ARGUMENT: if is_py3: arg = instruction.arg else: arg = ord(code[pc]) + ord(code[pc + 1]) * 256 + extended_arg extended_arg = 0 pc += opt_arg_size if op == dis.EXTENDED_ARG: extended_arg = arg * 65536 if debug: print(str(arg).rjust(5), end=' ') if op in dis.hasconst: print('(' + repr(co.co_consts[arg]) + ')', end=' ') elif op in dis.hasname: print('(' + co.co_names[arg] + ')', end=' ') elif op in dis.hasjrel: print('(to ' + repr(pc + arg) + ')', end=' ') elif op in dis.haslocal: print('(' + co.co_varnames[arg] + ')', end=' ') elif op in dis.hascompare: print('(' + dis.cmp_op[arg] + ')', end=' ') elif op in dis.hasfree: if free is None: free = co.co_cellvars + co.co_freevars print('(' + free[arg] + ')', end=' ') # Actually emulate the op. if state is None and states[start] is None: # No control reaches here (yet). if debug: print() continue state |= states[start] opname = dis.opname[op] jmp = jmp_state = None if opname.startswith('CALL_FUNCTION'): if sys.version_info < (3, 6): # Each keyword takes up two arguments on the stack (name and value). standard_args = (arg & 0xFF) + 2 * (arg >> 8) var_args = 'VAR' in opname kw_args = 'KW' in opname pop_count = standard_args + var_args + kw_args + 1 if depth <= 0: return_type = Any elif arg >> 8: # TODO(robertwb): Handle this case. return_type = Any elif isinstance(state.stack[-pop_count], Const): # TODO(robertwb): Handle this better. if var_args or kw_args: state.stack[-1] = Any state.stack[-var_args - kw_args] = Any return_type = infer_return_type(state.stack[-pop_count].value, state.stack[1 - pop_count:], debug=debug, depth=depth - 1) else: return_type = Any state.stack[-pop_count:] = [return_type] else: # Python 3.6+ if opname == 'CALL_FUNCTION': pop_count = arg + 1 if depth <= 0: return_type = Any else: return_type = infer_return_type(state.stack[-pop_count].value, state.stack[1 - pop_count:], debug=debug, depth=depth - 1) elif opname == 'CALL_FUNCTION_KW': # TODO(udim): Handle keyword arguments. Requires passing them by name # to infer_return_type. pop_count = arg + 2 return_type = Any elif opname == 'CALL_FUNCTION_EX': # TODO(udim): Handle variable argument lists. Requires handling kwargs # first. pop_count = (arg & 1) + 3 return_type = Any else: raise TypeInferenceError('unable to handle %s' % opname) state.stack[-pop_count:] = [return_type] elif opname == 'CALL_METHOD': pop_count = 1 + arg # LOAD_METHOD will return a non-Const (Any) if loading from an Any. if isinstance(state.stack[-pop_count], Const) and depth > 0: return_type = infer_return_type(state.stack[-pop_count].value, state.stack[1 - pop_count:], debug=debug, depth=depth - 1) else: return_type = typehints.Any state.stack[-pop_count:] = [return_type] elif opname in simple_ops: if debug: print("Executing simple op " + opname) simple_ops[opname](state, arg) elif opname == 'RETURN_VALUE': returns.add(state.stack[-1]) state = None elif opname == 'YIELD_VALUE': yields.add(state.stack[-1]) elif opname == 'JUMP_FORWARD': jmp = pc + arg jmp_state = state state = None elif opname == 'JUMP_ABSOLUTE': jmp = arg jmp_state = state state = None elif opname in ('POP_JUMP_IF_TRUE', 'POP_JUMP_IF_FALSE'): state.stack.pop() jmp = arg jmp_state = state.copy() elif opname in ('JUMP_IF_TRUE_OR_POP', 'JUMP_IF_FALSE_OR_POP'): jmp = arg jmp_state = state.copy() state.stack.pop() elif opname == 'FOR_ITER': jmp = pc + arg jmp_state = state.copy() jmp_state.stack.pop() state.stack.append(element_type(state.stack[-1])) else: raise TypeInferenceError('unable to handle %s' % opname) if jmp is not None: # TODO(robertwb): Is this guaranteed to converge? new_state = states[jmp] | jmp_state if jmp < pc and new_state != states[jmp] and jumps[pc] < 5: jumps[pc] += 1 pc = jmp states[jmp] = new_state if debug: print() print(state) pprint.pprint(dict(item for item in states.items() if item[1])) if yields: result = typehints.Iterable[reduce(union, Const.unwrap_all(yields))] else: result = reduce(union, Const.unwrap_all(returns)) finalize_hints(result) if debug: print(f, id(f), input_types, '->', result) return result
import dis def func_a(): a = list() return a def func_b(): b = [] return b # print(dis.dis("{}")) # print(dis.dis("dict()")) print(dis.dis(func_a)) print(dis.dis(func_b))
import dis, math, sys def square_root(x): return math.sqrt(x) print(f"function square_root() is located at: {square_root}") dis.dis(square_root) square_root = lambda x: math.sqrt(x) print(f"the lambda function of square_root() is located at: {square_root}") dis.dis(square_root) sum = lambda x, y: x + y # def sum(x,y): return x + y
foo() print(frame.f_code.co_name) caller_frame = frame.f_back print(caller_frame.f_code.co_name) def gen_func(): yield 1 name = "bobby" yield 2 age = 30 return "imooc" gen = gen_func() print(dis.dis(gen)) print(gen.gi_frame.f_lasti) print(gen.gi_frame.f_locals) next(gen) print(gen.gi_frame.f_lasti) print(gen.gi_frame.f_locals) next(gen) print(gen.gi_frame.f_lasti) print(gen.gi_frame.f_locals) class company: def __getitem__(self, item): pass
def add(a, b): c = a + b print(locals()) return c r = add(10,20) print(r) print(globals()) import dis print(add.__code__.co_varnames) dis.dis(add)
def show_js(ev): src = editor.getValue() doc["console"].value = dis.dis(src)
def test_expr(): import inspect, dis import math symtab = {'a.b.x': 1, 'a.c': 2, 'a.b': 3, 'b.x': 4} expr = 'a.b.x + sin(4*pi*a.c) + a.b.x/a.b' # Check symbol lookup assert _symbols(expr, symtab) == set([1, 2, 3]) # Check symbol rename assert _substitute(expr, {'a.b.x': 'Q'}) == 'Q + sin(4*pi*a.c) + Q/a.b' assert _substitute(expr, {'a.b': 'Q'}) == 'a.b.x + sin(4*pi*a.c) + a.b.x/Q' # Check dependency builder # Fake parameter class class Parameter: def __init__(self, name, value=0, expression=''): self.path = name self.value = value self.expression = expression def iscomputed(self): return (self.expression != '') def __repr__(self): return self.path def world(*pars): symtab = dict((p.path, p) for p in pars) exprs = dict((p.path, p.expression) for p in pars if p.iscomputed()) return symtab, exprs p1 = Parameter('G0.sigma', 5) p2 = Parameter('other', expression='2*pi*sin(G0.sigma/.1875) + M1.G1') p3 = Parameter('M1.G1', 6) p4 = Parameter('constant', expression='2*pi*35') # Simple chain assert set(_find_dependencies(*world(p1, p2, p3))) == set([(p2.path, p1), (p2.path, p3)]) # Constant expression assert set(_find_dependencies(*world(p1, p4))) == set([(p4.path, None)]) # No dependencies assert set(_find_dependencies(*world(p1, p3))) == set([]) # Check function builder fn = compile_constraints(*world(p1, p2, p3)) # Inspect the resulting function if 0: print(inspect.getdoc(fn)) print(dis.dis(fn)) # Evaluate the function and see if it updates the # target value as expected fn() expected = 2 * math.pi * math.sin(5 / .1875) + 6 assert p2.value == expected, "Value was %s, not %s" % (p2.value, expected) # Check empty dependency set doesn't crash fn = compile_constraints(*world(p1, p3)) fn() # Check that constants are evaluated properly fn = compile_constraints(*world(p4)) fn() assert p4.value == 2 * math.pi * 35 # Check additional context example; this also tests multiple # expressions class Table: Si = 2.09 values = {'Si': 2.07} tbl = Table() p5 = Parameter('lookup', expression="tbl.Si") fn = compile_constraints(*world(p1, p2, p3, p5), context=dict(tbl=tbl)) fn() assert p5.value == 2.09, "Value for %s was %s" % (p5.expression, p5.value) p5.expression = "tbl.values['Si']" fn = compile_constraints(*world(p1, p2, p3, p5), context=dict(tbl=tbl)) fn() assert p5.value == 2.07, "Value for %s was %s" % (p5.expression, p5.value) # Verify that we capture invalid expressions for expr in [ 'G4.cage', 'M0.cage', 'M1.G1 + *2', 'piddle', '5; import sys; print "p0wned"', '__import__("sys").argv' ]: try: p6 = Parameter('broken', expression=expr) fn = compile_constraints(*world(p6)) fn() except Exception as msg: #print(msg) pass else: raise "Failed to raise error for %s" % expr
import dis import base64 try: TUBY = TUBY # @UndefinedVariable except Exception: from tuby.core import TubyStream TUBY = TubyStream() dis.dis(base64.b64decode(''.join([l.strip() for l in TUBY.stdin])))
# Time Complexity of list, set, dict https://wiki.python.org/moin/TimeComplexity >>> from dis import dis >>> >>> c1 = '"hello" == "HELLO"' >>> c1 = compile(c1, '', 'exec') >>> dis(c1) 1 0 LOAD_CONST 0 ('hello') 3 LOAD_CONST 1 ('HELLO') 6 COMPARE_OP 2 (==) 9 POP_TOP 10 LOAD_CONST 2 (None) 13 RETURN_VALUE >>> c2 = '3 in [1,2,3]' >>> c2 = compile(c2, '', 'exec') >>> dis(c2) 1 0 LOAD_CONST 0 (3) 3 LOAD_CONST 4 ((1, 2, 3)) 6 COMPARE_OP 6 (in) 9 POP_TOP 10 LOAD_CONST 3 (None) 13 RETURN_VALUE >>> PyObject * PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) { TARGET(COMPARE_OP) { w = POP();
print(y.__next__()) # So this is how this great for loop works right # when you say newlist = [ 1,'a','&','4'] for i in newlist: print(i) # This is what it does # calls __iter__ of newlist and assigns it to something # it then calls something.__next__ method of and # pushes the value to i # lets examine this to see if that indeed is true # not clear enough right - # Lets dig a little deeper import dis dis.dis('''newlist = [ 1,'a','&','4'] for i in newlist: print(i)''') # We will spend day 4 on this code but trust me this is exactly # what this is doing - what you are seeing is the byte code in a # readable format # we will implement our own iterator by the end of today after defining a class print(newlist[0:2]) # start from left and all upto right newlist = [ 1,'a','&','4'] dir(newlist) # so what does __reversed__ do print(newlist.__reversed__()) # gives me an object newlist = [ 1,'a','&','4'] y = newlist.__reversed__() dir(y) # so this has a mehod called __next__