2

I've searched and couldn't find a direct answer for my question, so apologies if this has already been posted/answered before. I'm working in python and i need to pass expressions that contain variables, but i don't want them to be immediately evaluated.

For example:

r = x*y

I want the program to remember that in order to calculate r, it needs to multiply x and y instead of explicitly calculating it at the time. I've tried using:

x = None
y = None
r = x*y

But this doesn't allow operations on the variables. I've managed it using strings and then using "eval" but its not a very elegant solution, and its also painfully slow. Is there a better way of doing this?

3
  • 3
    Have you tried lambda expressions (which are actually function objects)? Commented Jan 8, 2013 at 16:04
  • I asked a very similar question over a year ago, and got this most excellent answer that got way less votes than it deserved. Commented Jan 9, 2013 at 8:04
  • What is your real goal here? I think there would be a much cleaner solution if you could tell us. I think you have a design problem, not a python problem. Commented Jan 9, 2013 at 8:07

2 Answers 2

4

You could use a lambda expression:

>>> x = None
>>> y = None
>>> r = lambda : x*y
>>> r()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
TypeError: unsupported operand type(s) for *: 'NoneType' and 'NoneType'
>>> x = 1
>>> y = 2
>>> r()
2

You could even get a little more fancy with a class:

class DeferredEval(object):
    def __init__(self,func):
        self.func = func

    def __call__(self):
        return self.func()

    def __add__(self,other):
        return self.func() + other

    def __radd__(self,other):
        return other + self.func()


x = None
y = None
r = DeferredEval(lambda:x*y)

try:
    a = 1 + r
except TypeError as err:
    print "Oops, can't calculate r yet -- Reason:",err

x = 1
y = 2
print 1 + r
print r + 1

with the output:

Oops, can't calculate r yet -- Reason: unsupported operand type(s) for *: 'NoneType' and 'NoneType'
3
3

Of course, here you'll need to add a whole bunch more methods if you want to do things that aren't addition, subtraction, ... Of course, then you have to actually call r in order to get your result -- but that's not so bad is it?

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks very much for your help, it was extremely useful. I need to also be able to edit the expressions, which i don't think is possible using lambda, but your example of a class has provided a lot of food for thought. Cheers.
@NathanBush -- What do you mean "edit" the expression? You can always just replace it with a new one: r = lambda : x+y.
0

You might look at the source code of the Math Evaluator utility to get an idea how to create expressions for evaluation later on. This demonstration on Ideone.com helps to show what the code can accomplish.

if __name__ == '__main__':
    # Run a simple demo that shows evaluator's capability.
    namespace = {}
    expression = tokens('x * y -> r')
    print expression
    evaluate('2 -> x; 3 -> y', namespace)
    expression.evaluate(namespace)
    print 'r =', namespace['r']
    alternate = Operation(Operation(Variable('x'), '+', Variable('y')), '->', Variable('r'))
    print alternate
    alternate.evaluate(namespace)
    print 'r =', namespace['r']

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.