I would suggest a two-step approach: in the first step, use the Python tokenize module to convert all floating-point numeric literals to source in the form string 'Decimal(my_numeric_literal)' . Then you can work on AST in the way that you propose.
There's even a recipe for the first step in the tokenize module. To avoid answering only the link, here is the code from this recipe (along with the necessary import, which the recipe itself is missing):
from cStringIO import StringIO from tokenize import generate_tokens, untokenize, NAME, NUMBER, OP, STRING def is_float_literal(s): """Identify floating-point literals amongst all numeric literals.""" if s.endswith('j'): return False
The original recipe identifies floating point literals by checking for the existence of the value '.' in meaning. This is not entirely bulletproof since it excludes literals like '1e10' and includes imaginary literals like 1.0j (which you can exclude). I replaced this check with my own version in is_float_literal above.
Having tried this in your example line, I get the following:
>>> expr = '100.50*num*discount' >>> decistmt(expr) "Decimal ('100.50')*num *discount "
... which you can now analyze in the AST tree as before:
>>> tree = ast.parse(decistmt(expr), mode='eval') >>>
and finally rate:
>>> from decimal import Decimal >>> locals = {'Decimal': Decimal, 'num': 3, 'discount': Decimal('0.1')} >>> eval(compile(tree, 'dummy.py', 'eval'), locals) Decimal('30.150')
source share