Ian P
Ian P

Reputation: 1533

Passing expressions to functions

In SQLAlchemy, it appears I'm supposed to pass an expression to filter() in certain cases. When I try to implement something like this myself, I end up with:

>>> def someFunc(value):
...     print(value)

>>> someFunc(5 == 5)
True

How do I get the values passed to == from inside the function?

I'm trying to achieve something like this

 >>> def magic(left, op, right):
 ...    print(left + " " + op + " " + right)

 >>> magic(5 == 5)
 5 == 5

What about if one of the parameters was an object?

Upvotes: 25

Views: 18201

Answers (7)

Kashif Ali
Kashif Ali

Reputation: 157

you can use __eq__ function to achieve this, and as for SQLAlchemy, they might be doing something like this



class Column(object):

    def __eq__(self, other):
        print("Perform and return custom logic here")
        return self.value == other

    def __set__(self, instance, value):
        self.value = value

    def __repr__(self):
        return self.value


class Model:
    id = Column()
    name = Column()

    def __init__(self, *args, **kwargs):
        for attr in kwargs.items():
            if getattr(self, attr[0]):
                setattr(self, attr[0], attr[1])

test = Model(id=10, name="test")

print(test.id == 10)
print(test.name)


Upvotes: 0

Nelson
Nelson

Reputation: 29806

You can achieve your example if you make "op" a function:

>>> def magic(left, op, right):
...     return op(left, right)
...
>>> magic(5, (lambda a, b: a == b), 5)
True
>>> magic(5, (lambda a, b: a == b), 4)
False

This is more Pythonic than passing a string. It's how functions like sort() work.

Those SQLAlchemy examples with filter() are puzzling. I don't know the internals about SQLAlchemy, but I'm guessing in an example like query.filter(User.name == 'ed') what's going on is that User.name is a SQLAlchemy-specific type, with an odd implementation of the __eq() function that generates SQL for the filter() function instead of doing a comparison. Ie: they've made special classes that let you type Python expressions that emit SQL code. It's an unusual technique, one I'd avoid unless building something that's bridging two languages like an ORM.

Upvotes: 37

WangST
WangST

Reputation: 188

You have to implement __eq__() . For example ::

class A(object):
    def __eq__(self, other):
        return (self, '==', other)

Then, for the function, which you want to get the expression, like ::

def my_func(expr):
    # deal with the expression
    print(expr)

>>> a = A()
>>> my_func(a == 1)
(<__main__.A object at 0x1015eb978>, '==', 1)

Upvotes: 4

Ned Deily
Ned Deily

Reputation: 85125

An even more pythonic variant of Nelson's solution is to use the operator functions from the operator module in the standard library; there is no need to create your own lambdas.

>>> from operator import eq
>>> def magic(left, op, right):
...   return op(left, right)
... 
>>> magic(5, eq, 5)
True

Upvotes: 10

Ian P
Ian P

Reputation: 1533

It appears you can return tuples from eq:

class Foo:
    def __init__(self, value):
            self.value = value

    def __eq__(self, other):
            return (self.value, other.value)


f1 = Foo(5)
f2 = Foo(10)
print(f1 == f2)

Upvotes: 1

balpha
balpha

Reputation: 50958

You can't. The expression 5 == 5 is evaluated and only then is the result passed to someFunc. The function just gets True (the True object, to be precise), no matter what the expression was.

Edit: Concerning your edit, this question is kind of close.

Edit 2: You could just pass the expression as a string and use eval, like this:

>>> def someFunc(expression_string):
...    print(expression_string, "evaluates to", eval(expression_string))

>>> someFunc("5 == 5")
5 == 5 evaluates to True

Don't know whether that helps you. Keep in mind that eval is a powerful tool, so it's dangerous to pass arbitrary (and possibly even user-generated) input to it.

Upvotes: 3

Brandon E Taylor
Brandon E Taylor

Reputation: 25379

Short answer: You can't. The result of the expression evaluation is passed to the function rather than the expression itself.

Upvotes: 0

Related Questions