views:

341

answers:

5

I read Storm ORM's tutorial at https://storm.canonical.com/Tutorial, and I stumbled upon the following piece of code :


store.find(Person, Person.name == u"Mary Margaret").set(name=u"Mary Maggie")

I'm not sure that the second argument of the find method will be evaluated to True/False. I think it will be interpreted as a lambda. If that is true, how can I achieve the same effect in my functions ?

A: 

since I'm a Java programmer... I'm guessing... it is operator overloading? Person.name == is an operator overloaded that instead do comparison... it produces a SQL query

my 0.02$

dfa
Java and operator overloading ... don't think it will ever come true. On the other side, maybe you are right .
Geo
Odd.... Accepting a "guessing" answer when another answer is based on the actual source code in Storm.
S.Lott
sorry, but my guess was "fast enough" :-) PS you're right, it's very odd!
dfa
In fairness, the guessing answer *is* correct, even if it's not the most clear.
Jason Baker
+1  A: 

It does not look like a python lambda to me. I did not read the code for Storm but Miles is probably right in that it uses a lazy evaluation schema.

To learn more about python lambda functions read the excellent chapter of Dive Into Python.

lothar
I always thought that lambda functions had to be prefixed by the lambda keyword, so this could not be the case, right?
Geo
+22  A: 

Person.name has a overloaded __eq__ method that returns not a boolean value but an object that stores both sides of the expression; that object can be examined by the find() method to obtain the attribute and value that it will use for filtering. I would describe this as a type of lazy evaluation pattern.

In Storm, it is implemented with the Comparable object.

Miles
+8  A: 

The magic is in the Person.name property, which results in a type that overloads __eq__ (&c) to return non-bools. Storm's sources are online for you to browse (and CAUTIOUSLY imitate;-) at http://bazaar.launchpad.net/~storm/storm/trunk/files/head%3A/storm/ -- as you'll see, they don't go light on the "black magic";-)

Alex Martelli
+9  A: 

Person.name is an instance of some type with a custom __eq__ method. While __eq__ normally returns a boolean(ish) value, it can actually return whatever you want, including a lambda. See Python special method names for more on this and related methods.

Probably the most confusing/misleading part of this (especially if you're used to other OO languages like Java) is that Person.name and person.name (where person is an instance of Person) don't have to have any relationship to each other. For example:

class Person(object):
  name = "name of class"
  def __init__(self):
    self.name = "name of instance"

person = Person()
print Person.name
print person.name

This will print:

name of class
name of instance

Note that the class property is just set in the class body, while the instance property is set in the __init__ method.

In your case, you'd set Person.name to the object with the custom __eq__ method that returns a lambda, something like this:

class LambdaThingy(object):
  def __init__(self, attrname):
    self.__attrname = attrname

  def __eq__(self, other):
    return lambda x: getattr(x, self.__attrname) == other

class Person(object):
  name = LambdaThingy('name')

  def __init__(self, name):
    self.name = name

equals_fred = Person.name == "Fred"
equals_barney = Person.name == "Barney"

fred = Person("Fred")

print equals_fred(fred)
print equals_barney(fred)

This prints:

True
False

This is certainly skirting the edge of being "too clever", so I'd be very cautious about using this in production code. An explicit lambda would probably be a lot clearer to future maintainers, even if it is a bit more verbose.

Laurence Gonsalves
+1 for the great explanation of the "too clever" part!
lothar