Re: Using eval with substitutions

2006-09-02 Thread Anthra Norell

- Original Message -
From: Carl Banks [EMAIL PROTECTED]
Newsgroups: comp.lang.python
To: python-list@python.org
Sent: Saturday, September 02, 2006 6:33 AM
Subject: Re: Using eval with substitutions


 [EMAIL PROTECTED] wrote:
   a,b=3,4
   x=a+b
...
  Careful.  Here be dragons.
...
 However, this is just a big potentially dangerous hack.  It's probably
...

 Carl Banks

---

Dragons indeed!
  To wit, I did get carried away a little with my suggestions and derived a 
class Formlua_Expander from SE. A few hours later it
worked just beautifully:

 FE = FORMEX.Formula_Expander ()
 FE.define ('l=102.8')
 FE.define ('d=8.5')
 FE.define ('pi=3.14159')
 FE.define ('r=d/2')
 FE.define ('section=r*r*pi')
 FE.define ('pipe_volume=l*section')
 FE ('pipe_volume')
5833.382851746
 FE.expand ('pipe_volume')
'((102.8)*(((8.5)/2)*((8.5)/2)*(3.14159)))'

The expansion cascade:

Data Chain
--
  pipe_volume
0 

  (l*section)
1 

  (l*(r*r*pi))
2 

  (l*((d/2)*(d/2)*pi))
3 

  ((102.8)*(((8.5)/2)*((8.5)/2)*(3.14159)))
--

Wonderful! Some more:

 FE.define ('m_per_foot=0.3048')
 FE.define ('pipe_volume_metric=pipe_volume*m_per_foot')
 FE ('pipe_volume_metric')

Traceback (most recent call last):
  File pyshell#199, line 1, in -toplevel-
FE ('pipe_volume_metric')
  File c:\i\sony\fre\src\python\FORMEX.py, line 175, in __call__
try: return eval (expression)
  File string, line 1
(((102.8)*(((8.5)/2)*((8.5)/2)*(3.14159)))*m_pe((8.5)/2)_foot(102.8)e)
^
Oops!

 FE.show (1)
...
(1st pass) ...
1: |pipe_volume_metric|-|(pipe_volume*m_per_foot)|
(2nd pass) ...
1: |pipe_volume|-|(l*section)|
(3rd pass) ...
1: |section|-|(r*r*pi)|
(4th pass) ...
1: |r|-|(d/2)|
(5th pass) ...
1: |d|-|(8.5)|
2: |l|-|(102.8)|
3: |m_per_foot|-|(0.3048)|
4: |pi|-|(3.14159)|

Data Chain
--
  pipe_volume_metric
0 

  (pipe_volume*m_per_foot)
1 

  ((l*section)*m_per_foot)
2 

  ((l*(r*r*pi))*m_per_foot)
3 

  ((l*((d/2)*(d/2)*pi))*m_pe(d/2)_foot)
4 

  (((102.8)*(((8.5)/2)*((8.5)/2)*(3.14159)))*m_pe((8.5)/2)_foot(102.8)e)
--

An unwanted substitution occurs in pass 4 when the 'r' in 'm_per_foot' is 
replaced
by the substitution meant for 'r' (radius).

Conclusion: Forget it! - Forget this approach anyway. There are probably 
formula parsers out there that are more intelligent than
this hack.

Frederic

(Learning by making mistakes is faster than by avoiding mistakes and if it's 
fun on top of it all the better.)


-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Using eval with substitutions

2006-09-01 Thread abhishek
Thanks very much for all your suggestions - Peter, Duncan and Frederic.
It was a great help.

Incidentally the question arose while I was trying to solve the 2-nots
problem,
http://www.inwap.com/pdp10/hbaker/hakmem/boolean.html#item19

Part of my program takes a set of boolean expressions in 3 variables
and keeps concatenating them with 'and' and 'or' until all unique
functions have been found. Sometimes it is good to use substitutions
(though not required) to make the patterns apparent. Anyway, the
listing is here,

http://www.ocf.berkeley.edu/~abhishek/twonot3.py

Abhishek

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Using eval with substitutions

2006-09-01 Thread Carl Banks
[EMAIL PROTECTED] wrote:
  a,b=3,4
  x=a+b
  eval(x)
 7
  y=x+a

 Now I want to evaluate y by substituting for the evaluated value of x.
 eval(y) will try to add a+b to 3 and return an error. I could do
 this,
  eval(y.replace(x,str(eval(x
 10

 but this becomes unwieldy if I have
  w=y*b
 and so on, because the replacements have to be done in exactly the
 right order. Is there a better way?

Careful.  Here be dragons.

There are two legitimate uses for eval and exec: A. deliberately giving
the user the power to run arbitrary Python code, and B. evaluating
expressions constructed within the program using only trusted and
carefully verified input.  Make sure your use case is one of these.

Anyways, although what you want to do is even more error prone and
dangerous than simple uses of eval, it can be done.  The thing to do is
to get your list of active symbol definitions into some kind of dict;
for example:

x = a+b
y = x+b
exprs = { x: x, y: y }

Then, if you want to evaluate y, you recursively expand any variables
you find within it. For example:

def expand_sym(sym):
expr = exprs[sym]
for subsym in exprs:
if subsym in expr:
subexpr = expand_sym(subsym)
expr = expr.replace(subsym,(%s) % subexpr)
return expr

Then you can eval the expanded expression:

eval(expand_sym(y))


However, this is just a big potentially dangerous hack.  It's probably
ok for a little calculator you intend only for personal use, but
anything more I highly recommend your script parses the expression and
does symbolic expansion itself, without relying on eval.  That,
however, is quite hard.


Carl Banks

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Using eval with substitutions

2006-08-31 Thread Fredrik Lundh
[EMAIL PROTECTED] wrote:

 a,b=3,4
 x=a+b
 eval(x)
 7
 y=x+a
 
 Now I want to evaluate y by substituting for the evaluated value of x.
 eval(y) will try to add a+b to 3 and return an error. I could do
 this,
 eval(y.replace(x,str(eval(x
 10
 
 but this becomes unwieldy if I have
 w=y*b
 and so on, because the replacements have to be done in exactly the
 right order. Is there a better way?

instead of

x = a+b

do

x = a+b
x = eval(x)


or

x = eval(a+b)

(I'm afraid I don't really understand the point of your examples; what 
is it you're really trying to do here ?)

/F

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Using eval with substitutions

2006-08-31 Thread abhishek
Fredrik Lundh wrote:
 (I'm afraid I don't really understand the point of your examples; what
 is it you're really trying to do here ?)

A function is passed a bunch of string expressions like,
x = a+b
y=  x*a
z= x+y

where a and b are assumed to have been assigned values in the local
namespace. Now I have to evaluate another string such as,
z+y+x

So as you say, I could do:
x=eval(x), y=eval(y), z=eval(z) and finally eval(z+y+x) but the
problem is that the initial strings are in no particular order, so I
don't know the sequence in which to perform the first 3 evaluations. I
was wondering if there was a simple way to 'pattern-match' so that the
required substitutions like z-x+y-x+x*a-(a+b)+(a+b)*a could be done
automatically.

I apologise if this is still not quite clear.

Abhishek

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Using eval with substitutions

2006-08-31 Thread Peter Otten
[EMAIL PROTECTED] wrote:

 Fredrik Lundh wrote:
 (I'm afraid I don't really understand the point of your examples; what
 is it you're really trying to do here ?)
 
 A function is passed a bunch of string expressions like,
 x = a+b
 y=  x*a
 z= x+y
 
 where a and b are assumed to have been assigned values in the local
 namespace. Now I have to evaluate another string such as,
 z+y+x
 
 So as you say, I could do:
 x=eval(x), y=eval(y), z=eval(z) and finally eval(z+y+x) but the
 problem is that the initial strings are in no particular order, so I
 don't know the sequence in which to perform the first 3 evaluations. I
 was wondering if there was a simple way to 'pattern-match' so that the
 required substitutions like z-x+y-x+x*a-(a+b)+(a+b)*a could be done
 automatically.

Here is something to start with:

class EvalDict(object):
def __init__(self, namespace):
self.namespace = namespace
def __getitem__(self, key):
value = self.namespace[key]
if isinstance(value, str):
self.namespace[key] = value = eval(value, {}, self)
return value

def smart_eval(expr, namespace):
return eval(expr, {}, EvalDict(namespace))

def f():
a = 2
b = 3
x = a+b
y = x*a
z = x+y

return smart_eval(x + y + z, locals())

if __name__ == __main__:
print f()

Beware of infinite recursion:

# RuntimeError: maximum recursion depth exceeded
smart_eval(a + b, dict(a=b, b=a)) 

Peter
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Using eval with substitutions

2006-08-31 Thread Duncan Booth
[EMAIL PROTECTED] wrote:

 So as you say, I could do:
 x=eval(x), y=eval(y), z=eval(z) and finally eval(z+y+x) but the
 problem is that the initial strings are in no particular order, so I
 don't know the sequence in which to perform the first 3 evaluations. I
 was wondering if there was a simple way to 'pattern-match' so that the
 required substitutions like z-x+y-x+x*a-(a+b)+(a+b)*a could be done
 automatically.
 
Sounds a bit of an odd thing to do, but:

 def evaluate(var, names):
expr = names[var]
names['__builtins__'] = {}
if isinstance(expr, basestring):
del names[var]
code = compile(expr, %s%var, eval)
for v in code.co_names:
evaluate(v, names)
names[var] = eval(code, names, names)
del names['__builtins__']
return names[var]

 names = { 'a': 3, 'b': 2, 'x': 'a+b', 'y': 'x*a', 'z': 'x+y' }
 evaluate('z', names)
20
 names
{'a': 3, 'b': 2, 'y': 15, 'x': 5, 'z': 20}
 

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Using eval with substitutions

2006-08-31 Thread Anthra Norell
Abhishek,

  I hesitate to propose this idea, because there's got to be a better (more 
conventional) way of doing this. Anyway consider
this:

 x = a+b; y = x*a; z = x+y   # Your definitions
 import SE
 def  f  (x, y, z):
 substitutions = 'z=(%s) | y=(%s) | x=(%s)' % (z, y, x)
 print 'substitutions:', substitutions
 Formula_Expander = SE.SE (substitutions)
 formula = 'x + y + z'
 expanded_formula = Formula_Expander (formula)
 print 'expanded_formula:', expanded_formula
 a = 3; b = 4
 print 'eval (expanded_formula):', eval (expanded_formula)
 w = eval (Formula_Expander ('y * b'))
 print 'w', w

 f (x, y, z)
substitutions: z=(x+y) | y=(x*a) | x=(a+b)
expanded_formula: (a+b) + ((a+b)*a) + ((a+b)+((a+b)*a))
eval (expanded_formula): 56
w 84

Well--- it's kind of neat the way it expands the formula. But why not just 
write functions? As you say, the expansion has to be done
in exactly the right order to complete.
  If you want to run this example you'll find SE here: 
http://cheeseshop.python.org/pypi/SE/2.2%20beta

Regards

Frederic



- Original Message -
From: [EMAIL PROTECTED]
Newsgroups: comp.lang.python
To: python-list@python.org
Sent: Thursday, August 31, 2006 1:15 PM
Subject: Using eval with substitutions


  a,b=3,4
  x=a+b
  eval(x)
 7
  y=x+a

 Now I want to evaluate y by substituting for the evaluated value of x.
 eval(y) will try to add a+b to 3 and return an error. I could do
 this,
  eval(y.replace(x,str(eval(x
 10

 but this becomes unwieldy if I have
  w=y*b
 and so on, because the replacements have to be done in exactly the
 right order. Is there a better way?

 Thanks,
 Abhishek

 --
 http://mail.python.org/mailman/listinfo/python-list

-- 
http://mail.python.org/mailman/listinfo/python-list