Разобрать эту строку в дереве (или эквивалентно интерпретируемой структуре данных), всего один раз, а затем повторно использовать функцию для «интерпретации дерева» для каждого интересующего набора назначений переменных. (Вы даже можете сгенерировать байт-код Python в качестве «интерпретируемой структуры данных», так что вы можете просто использовать eval
в качестве «интерпретации дерева» - что делает для медленной генерации, но это требуется только один раз, и для быстрой интерпретации). *
Как вы говорите, это немного абстрактно, поэтому давайте приведем конкретный, хотя и упрощенный пример. Скажем, например, что переменные - это буквы x, y, z, t, а операторы - для сложения и s для вычитания - строки смежных букв неявно означают высокоприоритетное умножение, как в общем математическом соглашении; нет круглых скобок и строгое выполнение слева направо (т.е. нет приоритета оператора, кроме умножения). Каждый символ кроме этих 6 должен игнорироваться. Итак, вот очень специальный анализатор и генератор байт-кода Python:
class BadString(Exception): pass
def makeBytecode(thestring):
theoperator = dict(a='+', s='-')
python = []
state = 'start'
for i, letter in enumerate(thestring):
if letter in 'xyzt':
if state == 'start':
python.append(letter)
state = 'variable'
elif state == 'variable':
python.append('*')
python.append(letter)
elif letter in 'as':
if state == 'start':
raise BadString(
'Unexpected operator %r at column %d' % (letter, i))
python.append(theoperator[letter])
state = 'start'
if state != 'variable':
raise BadString(
'Unexpected operator %r at end of string' % letter)
python = ''.join(python)
# sanity check
# print 'Python for %r is %r' % (thestring, python)
return compile(python, thestring, 'eval')
Теперь вы можете просто вызвать eval
с результатом этого в качестве первого аргумента и с помощью dict, связывающего значения с x, y, z и t в качестве второго аргумента. Например (импортировав вышеупомянутый модуль как par
и раскомментировав проверку работоспособности):
>>> c=par.makeBytecode('xyax')
Python for 'xyax' is 'x*y+x'
>>> for x in range(4):
... for y in range(5):
... print 'x=%s, y=%s: result=%s' % (x,y,eval(c,dict(x=x,y=y)))
...
x=0, y=0: result=0
x=0, y=1: result=0
x=0, y=2: result=0
x=0, y=3: result=0
x=0, y=4: result=0
x=1, y=0: result=1
x=1, y=1: result=2
x=1, y=2: result=3
x=1, y=3: result=4
x=1, y=4: result=5
x=2, y=0: result=2
x=2, y=1: result=4
x=2, y=2: result=6
x=2, y=3: result=8
x=2, y=4: result=10
x=3, y=0: result=3
x=3, y=1: result=6
x=3, y=2: result=9
x=3, y=3: result=12
x=3, y=4: result=15
>>>
Более сложный, но все же простой !, анализ строки & построение быстро интерпретируемой структуры данных, см., Например, pyparsing .