Reputation: 595
I am a little confused about the utility of the python @*.getter
syntax versus simply defining a property without a getter.
To investigate this, let's write a very simple class:
class Foo:
def __init__(self):
self._x = None
@property
def x(self):
print('Attribute `self.x` is a property.')
return self._x
@x.getter
def x(self):
print('Getting property `x`...')
return self._x
Now, if I try to instantiate the class and get the property x
from the instance, we see that the getter method is called:
>>> A = Foo()
>>> print(A.x)
Getting property `x`...
None
Okay, so what? That's exactly what we ought to expect.
However, if I define the exact same class without any getter method, we get something different:
>>> print(A.x)
Attribute `self.x` is a property.
None
When no getter method is defined, attempting to retrieve the property results in the 'property definition method' (I mean the method defined under @property
, for lack of a better name) getting called instead.
Interestingly, in the first case, the method defined under @property
is never actually called.
So, then, what is the point of having a special getter method if the original property definition seems to serve as a getter in its absence? Does the original definition serve any purpose other than simply to say, "this is a property"? Are there any other circumstances when this method would be called (besides property retrieval in the absence of a getter)? Why would you choose to use a getter versus simply incorporating its functionalities into the property definition?
Lastly, are there any use cases when one would use a property definition method that is any more complex than the following canonical form, while also using an @*.getter
method?
@property
def x(self): return self._x
Upvotes: 1
Views: 104
Reputation: 31354
Using the @x.getter
decorator tells Python that the following method is the intended getter for the property.
You're right that it's not very useful in the example you're giving. The @property
decorator does the same job and defines the property all in one go. There really is no reason to use both in a single class definition.
However, perhaps you want to override the getter method in a subclass?
class Foo:
def __init__(self, x):
self._x = x
@property
def x(self):
print('Attribute `self.x` is a property.')
return self._x
class Bar(Foo):
count: int = 0
@Foo.x.getter
def x(self):
Bar.count += 1
print(f'Getting Bar property `x` ({Bar.count})')
return self._x
foo = Foo(10)
print(foo.x)
bar = Bar(10)
print(bar.x)
print(bar.x)
Output:
Attribute `self.x` is a property.
10
Getting Bar property `x` (1)
10
Getting Bar property `x` (2)
10
There are several other use cases where defining the getter explicitly makes sense, even though in the base case you just use @property
and @attr.setter
.
The counter is just there to show a simple reason why you might want to modify the getter behaviour, even if it doesn't modify the actual value of the property.
Upvotes: 1