3

Update:
Thanks for the responses. I think it finally helped make things click in my head now.

Python prescribes this workflow:

  1. start by just using properties and avoid over-engineering with boilerplate getter/setter
  2. when more logic is necessary, switch over to getter/setter using the @property decorator to maintain a consistent API to reduce refactoring

As oppose to these workflows:

  1. start out using getter/setter to avoid refactoring later.
    • this adds unnecessary boilerplate code that might never be needed

or

  1. start out using properties
  2. switch to non-@property getter/setter when more logic is necessary
  3. refactor all dependent code to use getter/setter instead of properties

Thanks again for helping me understand these timeline of events and the awesome usefulness of @property.

If either of you want to add an answer, I'll accept it to close this out. Thanks again

Original:

I've been reading up on Python's @property decorator.

I understand that it is useful to allow library users to get properties like class.property while allowing library maintainers to refactor the getter logic behind the property-like interface much like a getter method.

What I don't understand is, why go through the hassle of using decorators to achieve an interface that resembles a property, like class.property. What is wrong with have a normal method like interface, like class.property()?

Is there something I'm missing? I don't understand why the extra parenthesis in the method call is problematic enough to warrant using a decorator?

Maybe the following code can help explain what I'm trying to get at better?:

class Class:
    def __init__(self, value):
        self._value = value

    def value(self):
        return self._value

print(Class('calling method').value())

class Class:
    def __init__(self, value):
        self._value = value

    @property
    def value(self):
        return self._value

print(Class('accessing property').value)

Is it because it makes setters prettier? So instead of:
klass.set_value('some value')
you can have?:
klass.value = 'some value'

Like this example code?:

class Class:
    def __init__(self, value):
        self._value = value

    def value(self):
        return self._value

    def set_value(self, value):
        self._value = value

klass = Class('calling method')
klass.set_value('calling method2')
print(klass.value())

class Class:
    def __init__(self, value):
        self._value = value

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, value):
        self._value = value

klass = Class('accessing property')
klass.value = 'accessing property2'
print(klass.value)

Are the reasons to use the @property decorator purely to make the class interface more aesthetically pleasing?

I do think the interface ends up looking nicer, but I'm wondering if I'm missing something more.

Thank you for your time :)

Zhao Li
  • 4,936
  • 8
  • 33
  • 51
  • 1
    No. In both of these cases, you should use *neither a `property` nor getter/setter methods*. Because your *getter/setters don't do anything*. This should just be `self.value = value` in `__init__` with no `property` and access it `klass.value` – juanpa.arrivillaga Apr 14 '21 at 10:31
  • See for example https://stackoverflow.com/questions/6618002/using-property-versus-getters-and-setters – Thierry Lathuille Apr 14 '21 at 10:32
  • The *whole point* of `property` is to provide *encapsulation without boilerplate getters and setters*. So you have your class, with your value, and when you create it you only need simple access and modification. Now, if *at some point* you want to control the access of `self.value`, you can *then* use a property which has some non-trivial getter or setter, *without breaking the rest of your class implementation*. – juanpa.arrivillaga Apr 14 '21 at 10:33
  • 1
    Thanks @juanpa.arrivillaga and Thierry Lathuille. I've updated the question based on your comments. Please feel free to write an answer to close this out. – Zhao Li Apr 14 '21 at 19:13

1 Answers1

1

I'll just post an answer to close out this thread, since the commenters seem like they are busy:

Python prescribes this workflow:

  1. start by just using properties and avoid over-engineering with boilerplate getter/setter
  2. when more logic is necessary, switch over to getter/setter using the @property decorator to maintain a consistent API to reduce refactoring

As oppose to these workflows:

  1. start out using getter/setter to avoid refactoring later.
    • this adds unnecessary boilerplate code that might never be needed

or

  1. start out using properties
  2. switch to non-@property getter/setter when more logic is necessary
  3. refactor all dependent code to use getter/setter instead of properties

I hope this helps others better understand the reason Python prescribes the use of @property.

Zhao Li
  • 4,936
  • 8
  • 33
  • 51