flawr
flawr

Reputation: 11628

Is it possible to call setter as a method?

Given following class, I can modify _x using the setter/getter construct. But is it now possible to change _x by calling a method?

The reason I'm asking is just because it would later be very convenient to define something as a lambda using lambda y: (c.x := y) which works in 3.8, but in 3.7 we'd need something like lambda y: c.x.some_method_maybe(y).

class C:
    def __init__(self):
        self._x = 0
    @property
    def x(self):
        return self._x
    @x.setter
    def x(self,_x):
        print(_x)
        self._x = _x
c = C()
c.x = 999 # this works
c.x.some_method_maybe(999) # call setter of x explicitly?

Upvotes: 1

Views: 1035

Answers (2)

Luisg123v
Luisg123v

Reputation: 123

You may take advantage of the property's fset attrybute by using something like the following:

C.x.fset(c, 999)

Upvotes: 1

Tadhg McDonald-Jensen
Tadhg McDonald-Jensen

Reputation: 21474

you can make the getter and setter normal methods then pack them into a property afterwards

class C:
    def __init__(self):
        self._x = 0

    def get_x(self): 
        "getter for property x, see `help(C.x)`"
        return self._x
    def set_x(self,_x):
        "setter for property x, see `help(C.x)`"
        print(_x)
        self._x = _x
    x = property(get_x,set_x, doc="""\
                documentation of property x here, 
                `help(C.x)` will print this""")

then you can use c.set_x as your callback and the property c.x still works as you expect.

But notice that the method was totally allowed to do self._x = _x because it was a function instead of a lambda so you could just do the same where you need a callback:

def modify(y): c.x = y

As long as you are ok defining your lambda on it's own line this is always a valid design pattern, to just declare a short function for your callbacks.

Alternatively if you love one liners and lambdas and hate readability you can use the __set__ magic method of the property on the class itself if you don't want to expose the setter directly.

modify = lambda val: type(c).x.__set__(c, val)

where type(c) gets the class object, .x gives the property object directly, .__set__ is the magic method called when you set the property of an instance, and you call it with the instance as the first argument as you'd expect calling methods on classes to work.

Upvotes: 3

Related Questions