James Franco James Franco - 2 months ago 10
Python Question

Python - Property Getter as a lambda with a parameter

Being new to python I just came across the

property
keyword which basically lets you assign getters and setters. I came up with this simple example

class foo:
def __init__(self,var=2):
self.var= var

def setValue(self,var):
print("Setting value called")
self._var = var

def getValue(self):
print("getting value")

var = property(getValue,setValue)


Now in my django project I came across with something like this (using a lambda in a property)

class UserProfile(models.Model):
user = models.OneToOneField(User)
likes_cheese = models.BooleanField(default=True)
puppy_name = models.CharField(max_length=20)

User.profile = property(lambda u : UserProfile.objects.get_or_create(user=u)[0])


I had no clue that you could use a lambda inside a property. Now from what I understand is that it is setting the getter of the
profile
as a lambda and the getter requires a parameter. This kind of confused me. So I decided to try my own example

class double:
def setValue(self,var):
print("Setting value called")
self._var = var

def getValue(self):
print("getting value")

#var = property(getValue,setValue)
var = property(lambda x: print("The value of parameter is" + str(x)))

d =double()
d.var #Call the getter but how do i pass a value parameter to it ?


Now in my case how can i pass a parameter to the lambda ?

Answer

The normal/idomatic way to write a property is:

class MyClass(object):
    def __init__(self):
        self._foo = 42

    @property
    def foo(self):
        return self._foo

    @foo.setter
    def foo(self, val):
        self._foo = val

as you can see, like all other method definitions in Python, the first parameter to the method is self.

You can name the parameter whatever you want (don't!), but the first parameter will always be the object itself.

The nice syntax above can be deconstructed to

class MyClass(object):
    def __init__(self):
        self._foo = 42

    def foo_get(self):
        return self._foo

    def foo_set(self, val):
        self._foo = val

    foo = property(foo_get, foo_set)

and instead of passing function names to property we can instead use lambdas:

class MyClass(object):
    def __init__(self):
        self._foo = 42

    def foo_set(self, val):
        self._foo = val

    foo = property(lambda self: self._foo, foo_set)

we can't pass the setter as a lambda since lambdas cannot contain assignments. Here I've continued using self as the parameter name, but I could use any variable name, e.g.:

foo = property(lambda u: u._foo, foo_set)