Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python why is a setter preferred?

The property decorator is a great way to "protect" attributes one wants to set once and never change again. I usually deal with this this way (btw., following a the advice here):

self._name = 'foo'

@property
def name(self):
    return self._name

so trying to set name directly yields an AttributeError.

However, I often see the following pattern:

@name.setter
def name(self, value):
    self._name = value

@property
def name(self):
    return self._name

which seems a little counter-intuitive, as it enables exactly what I want to avoid, and requires extra coding, i.e, theoretically

self.name = 'bar'

would suffice, although it is clear that this would be the worst way to deal with the problem.

The best explanation I can come up with is something like a message from the author saying "you should not change this attribute but if you really want to, there is a mechanism to do it without changing a 'protected' attribute". But then, python doesn't really protect attributes.

So, what's the point, which is more pythonic and why?

like image 524
jake77 Avatar asked Dec 13 '25 17:12

jake77


1 Answers

You're correct that there's no good reason to use a property if you're not doing anything special in the getter or setter. However, if you do want to do something special (like validate new values, or normalize them in some way), then it makes a lot of sense.

For example, this class's foo attribute will always be clamped between 0 and 1 (and non-numerical values will cause an error immediately):

class Foo:
    _foo = 1.0

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

    @foo.setter
    def foo(self, value):
        if value < 0:
            value = 0
        elif value > 1:
            value = 1
        self._foo = value

An example with a trivial setter, but a complicated getter might be something like this (deferring an expensive initialization that might not be needed):

class Foo:
    _foo = None

    def initialize_foo(self):
        self._foo = some_expensive_calculation()

    @property
    def foo(self):
        if self._foo is None:
            self.initialize_foo() # need the default value
        return self._foo

    @foo.setter
    def foo(self, value):
        self._foo = value
like image 138
Blckknght Avatar answered Dec 16 '25 18:12

Blckknght



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!