what python feature is illustrated in this code?
-
03-07-2019 - |
Question
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 ?
Solution
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$
OTHER TIPS
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.
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.
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";-)
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.