私は2段階アプローチを提案します。最初の手順では、Pythonのtokenize
モジュールを使用して、ソース内のすべての浮動小数点数値リテラルを'Decimal(my_numeric_literal)'
の文字列に変換します。次に、あなたが提案する方法でASTで作業することができます。
トークン化モジュールdocumentationの最初の手順のレシピがあります。の存在を確認することで
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 # Exclude imaginary literals.
elif '.' in s:
return True # It's got a '.' in it and it's not imaginary.
elif s.startswith(('0x', '0X')):
return False # Must be a hexadecimal integer.
else:
return 'e' in s # After excluding hex, 'e' must indicate an exponent.
def decistmt(s):
"""Substitute Decimals for floats in a string of statements.
>>> from decimal import Decimal
>>> s = 'print +21.3e-5*-.1234/81.7'
>>> decistmt(s)
"print +Decimal ('21.3e-5')*-Decimal ('.1234')/Decimal ('81.7')"
>>> exec(s)
-3.21716034272e-007
>>> exec(decistmt(s))
-3.217160342717258261933904529E-7
"""
result = []
g = generate_tokens(StringIO(s).readline) # tokenize the string
for toknum, tokval, _, _, _ in g:
if toknum == NUMBER and is_float_literal(tokval):
result.extend([
(NAME, 'Decimal'),
(OP, '('),
(STRING, repr(tokval)),
(OP, ')')
])
else:
result.append((toknum, tokval))
return untokenize(result)
オリジナルレシピは、浮動小数点リテラルを識別します。ここで(レシピ自体が欠落している必要が輸入品と一緒に)そのレシピからのコードだ、リンクだけの答えを回避するために、 '.'
の値。それはのようなリテラルを除外し、1.0j
のような想像上のリテラルを含みます(除外したいかもしれない)ので、完全に防弾ではありません。私はそのチェックを上記のis_float_literal
の自分のバージョンに置き換えました。
あなたの例の文字列でこれをしようと、私はこの取得:
>>> tree = ast.parse(decistmt(expr), mode='eval')
>>> # walk the tree to validate, make changes, etc.
...
>>> ast.dump(tree)
"Expression(body=BinOp(left=BinOp(left=Call(func=Name(id='Decimal', ...
し、最終的に評価する:あなたは今、以前のようにASTツリーに解析することができます
>>> expr = '100.50*num*discount'
>>> decistmt(expr)
"Decimal ('100.50')*num *discount "
...
を
>>> from decimal import Decimal
>>> locals = {'Decimal': Decimal, 'num': 3, 'discount': Decimal('0.1')}
>>> eval(compile(tree, 'dummy.py', 'eval'), locals)
Decimal('30.150')
ソースコード*の元の数字リテラルの意味を説明できますか? – Kasramvd
申し訳ございません。*数値リテラル*:https://docs.python.org/2/reference/lexical_analysis.html?highlight =リテラル#数値リテラル – jayven