On Sun, 28 Aug 2005 04:09:10 GMT, [EMAIL PROTECTED] (Bengt Richter) wrote: [... a response to the OP's apparent desire to "overload the divide operator" with a call to his safediv function ...]
The part that rewrote the the AugAssign could only work for plain name Augassign targets, so I introduced a helper function to generate a suitable assignment target node for attributes, subscripts, and slices as well. So the test (still very alpha) looks like the following now: ----< testdiv.py >------------------------------------------------------------------------- def test(): print 1.0/2.0 print 12/3 a=12; b=3 print a/b print 2**a/(b+1) try: print 'print 1/0 =>' print 1/0 except Exception, e: print '%s: %s' %(e.__class__.__name__, e) try: print 'print a/(b*(a-12)) =>' print a/(b*(a-12)) except Exception, e: print '%s: %s' %(e.__class__.__name__, e) try: print 'def foo(x=1/(b-3)): return x =>' def foo(x=1/(b-3)): return x print 'print foo() =>' print foo() except Exception, e: print '%s: %s' %(e.__class__.__name__, e) try: print 'b /= (a-12) =>' b /= (a-12) print 'b after b/=(a-12):', b except Exception, e: print '%s: %s' %(e.__class__.__name__, e) print 's=[15]; s[0] /= 3; print s =>' s=[15]; s[0] /= 3; print s class T(list): def __getitem__(self, i): print i; return 42 def __setitem__(self, i, v): print i, v def __div__(self, other): print self, other; return 4242 t = T() print 't.x=15; t.x /= 3; print t.x =>' t.x=15; t.x /= 3; print t.x print 't=T([15, 27]); t /= 3; print t =>' t=T([15, 27]); t /= 3; print t def foo(x, y): """for dis.dis to show code""" z = x/y x /= y x.a /= y x[z] /= y x[:] /= y if __name__ == '__main__': test() ------------------------------------------------------------------------------------------ Outputfrom run without conversion of / : ----< import_safediv.py >------------------------------------------------------------------ # import_safediv.py from arborist import import_editing_ast, get_augassign_tgt from compiler.ast import Div, CallFunc, Name, AugAssign, Assign def safediv(num, den): if den==0: result = 0*num else: result = num/den print 'safediv(%r, %r) => %r'%(num, den, result) return result def div2safediv(divnode): """replace Div nodes with CallFunc nodes calling safediv with same args""" return CallFunc(Name('safediv'),[divnode.left, divnode.right], None, None, divnode.lineno) def divaugass2safediv(auganode): if auganode.op != '/=': return auganode return Assign([get_augassign_tgt(auganode)], CallFunc(Name('safediv'),[auganode.node, auganode.expr], None, None, auganode.lineno)) callbacks = {Div:div2safediv, AugAssign:divaugass2safediv} def import_safediv(modname, verbose=False): modsafe = import_editing_ast(modname, callbacks, verbose) modsafe.safediv = safediv return modsafe if __name__ == '__main__': modsafe = import_safediv('testdiv', verbose=True) modsafe.test() ------------------------------------------------------------------------------------------- Result from using the above interactively: [14:21] C:\pywk\ut\ast>py24 Python 2.4b1 (#56, Nov 3 2004, 01:47:27) [GCC 3.2.3 (mingw special 20030504-1)] on win32 Type "help", "copyright", "credits" or "license" for more information. First import as usual and run test() >>> import testdiv >>> testdiv.test() 0.5 4 4 1024 print 1/0 => ZeroDivisionError: integer division or modulo by zero print a/(b*(a-12)) => ZeroDivisionError: integer division or modulo by zero def foo(x=1/(b-3)): return x => ZeroDivisionError: integer division or modulo by zero b /= (a-12) => ZeroDivisionError: integer division or modulo by zero s=[15]; s[0] /= 3; print s => [5] t.x=15; t.x /= 3; print t.x => 5 t=T([15, 27]); t /= 3; print t => [15, 27] 3 4242 Now import the import_safediv importer, to import with conversion of ast to effect translation of divides to safediv calls: Import and runs test() much as before: >>> from import_safediv import import_safediv >>> tdsafe = import_safediv('testdiv') >>> tdsafe.test() safediv(1.0, 2.0) => 0.5 0.5 safediv(12, 3) => 4 4 safediv(12, 3) => 4 4 safediv(4096, 4) => 1024 1024 print 1/0 => safediv(1, 0) => 0 0 print a/(b*(a-12)) => safediv(12, 0) => 0 0 def foo(x=1/(b-3)): return x => safediv(1, 0) => 0 print foo() => 0 b /= (a-12) => safediv(3, 0) => 0 b after b/=(a-12): 0 s=[15]; s[0] /= 3; print s => safediv(15, 3) => 5 [5] t.x=15; t.x /= 3; print t.x => safediv(15, 3) => 5 5 t=T([15, 27]); t /= 3; print t => [15, 27] 3 safediv([15, 27], 3) => 4242 4242 Look at the code generated by normal import first >>> import dis >>> dis.dis(testdiv.foo) 40 0 LOAD_FAST 0 (x) 3 LOAD_FAST 1 (y) 6 BINARY_DIVIDE 7 STORE_FAST 2 (z) 41 10 LOAD_FAST 0 (x) 13 LOAD_FAST 1 (y) 16 INPLACE_DIVIDE 17 STORE_FAST 0 (x) 42 20 LOAD_FAST 0 (x) 23 DUP_TOP 24 LOAD_ATTR 3 (a) 27 LOAD_FAST 1 (y) 30 INPLACE_DIVIDE 31 ROT_TWO 32 STORE_ATTR 3 (a) 43 35 LOAD_FAST 0 (x) 38 LOAD_FAST 2 (z) 41 DUP_TOPX 2 44 BINARY_SUBSCR 45 LOAD_FAST 1 (y) 48 INPLACE_DIVIDE 49 ROT_THREE 50 STORE_SUBSCR 44 51 LOAD_FAST 0 (x) 54 DUP_TOP 55 SLICE+0 56 LOAD_FAST 1 (y) 59 INPLACE_DIVIDE 60 ROT_TWO 61 STORE_SLICE+0 62 LOAD_CONST 1 (None) 65 RETURN_VALUE and then corresponding import_safediv (with same line numbers): >>> dis.dis(tdsafe.foo) 40 0 LOAD_GLOBAL 0 (safediv) 3 LOAD_FAST 0 (x) 6 LOAD_FAST 1 (y) 9 CALL_FUNCTION 2 12 STORE_FAST 3 (z) 41 15 LOAD_GLOBAL 0 (safediv) 18 LOAD_FAST 0 (x) 21 LOAD_FAST 1 (y) 24 CALL_FUNCTION 2 27 STORE_FAST 0 (x) 42 30 LOAD_GLOBAL 0 (safediv) 33 LOAD_FAST 0 (x) 36 LOAD_ATTR 4 (a) 39 LOAD_FAST 1 (y) 42 CALL_FUNCTION 2 45 LOAD_FAST 0 (x) 48 STORE_ATTR 4 (a) 43 51 LOAD_GLOBAL 0 (safediv) 54 LOAD_FAST 0 (x) 57 LOAD_FAST 3 (z) 60 BINARY_SUBSCR 61 LOAD_FAST 1 (y) 64 CALL_FUNCTION 2 67 LOAD_FAST 0 (x) 70 LOAD_FAST 3 (z) 73 STORE_SUBSCR 44 74 LOAD_GLOBAL 0 (safediv) 77 LOAD_FAST 0 (x) 80 SLICE+0 81 LOAD_FAST 1 (y) 84 CALL_FUNCTION 2 87 LOAD_FAST 0 (x) 90 STORE_SLICE+0 91 LOAD_CONST 1 (None) 94 RETURN_VALUE I guess this shows that code munging by AST rewriting is somewhat feasible, but you can probably expect to have to dig into dark corners ;-) I need to think through a few things I'm doing by intuition before I go much further... Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list