Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create properties using lambda getter and setter

I have something like this:

class X():
    def __init__(self):
        self.__name = None

    def _process_value(self, value):
        # do something
        pass

    def get_name(self):
        return self.__name

    def set_name(self, value):
        self.__name = self._process_value(value)

    name = property(get_name, set_name)

Can I replace get_name and set_name using lambda functions?

I've tried this:

name = property(lambda self: self.__name, lambda self, value: self.__name = self.process_value(value))

but compiler doesn't like my setter function.

like image 898
tefozi Avatar asked Aug 03 '09 22:08

tefozi


People also ask

Are getters and setters properties?

Accessor properties are represented by “getter” and “setter” methods. In an object literal they are denoted by get and set : let obj = { get propName() { // getter, the code executed on getting obj. propName }, set propName(value) { // setter, the code executed on setting obj.

Can Lambda take two arguments?

A lambda function can take any number of arguments, but can only have one expression.

Can Lambda have multiple inputs?

A lambda function can have any number of parameters, but the function body can only contain one expression.

Is @property a getter?

@property is used to get the value of a private attribute without using any getter methods. We have to put a line @property in front of the method where we return the private variable. To set the value of the private variable, we use @method_name.


2 Answers

Your problem is that lambda's body must be an expression and assignment is a statement (a strong, deep distinction in Python). If you insist on perpetrating lambdas you'll meet many such cases and learn the workarounds (there's usually one, though not always), such as, in this case:

name = property(lambda self: self.__name, 
                lambda self, value: setattr(self, 
                                            '_X__name',
                                            self.process_value(value)))

i.e. use the built-in setattr (which is a function and thus acceptable in a lambda's body) rather than assignment (which is a statement and thus unacceptable in a lambda's body).

You also need to perform the name-mangling for the dual-underscore attribute manually (changing __name to _X__name as you're in class X) where the attribute name is presented as a quoted string, as it must be in setattr, as the Pyhon compiler only does the name mangling in question for suitable identifiers, not for string literals.

like image 114
Alex Martelli Avatar answered Oct 12 '22 15:10

Alex Martelli


If you are extending a list, you can also use __setitem__, like this:

class Position(list):
    def __init__(self,x=0, y=0, z=0):
        super(Position, self).__init__((x,y,z))

    x = property(lambda self: self[0],
                 lambda self,value: self.__setitem__(0, value))
    y = property(lambda self: self[1],
                 lambda self,value: self.__setitem__(1, value))
    z = property(lambda self: self[2],
                 lambda self,value: self.__setitem__(2, value))
like image 24
Philipp Kewisch Avatar answered Oct 12 '22 15:10

Philipp Kewisch