Today at work I had a session where I explained properties in Python to data science colleagues who were not very familiar with OOP in Python. Among the questions I received, there was the simple issue of why in Python the setter/getter situation is a bit unintuitive.
For example, if you have field in a class it is an expected behaviour that a method prefixed with @property
will return a value of said field:
class Bar:
def __init__(self, a: int):
self._a = a
@property
def a(self):
return self._a
And then:
f = Bar(2)
print(f.a) # Out: 2
But what if you have a dedicated getter, like you would in other languages like Java or C#, it is sensible when you are trying to get a value of an attribute:
class Baz:
def __init__(self, a: int):
self._a = a
@property
def a(self):
return None
@a.getter
def a(self):
return self._a
And if we do:
bb = Baz(2)
print(bb.a) # Out: 2
Here it returns 2 despite the fact that the field prefixed with @property
supposedly returns None
.
Obviously, for people in the know the fact that @property
returns a value and the fact than getter is redundant in Python syntax is hardly an issue. And of course, the following doesn't work:
class Booz:
def __init__(self, a: int):
self.a = a
@a.getter
def a(self):
return self.a
bbb = Booz(2) # Out: NameError: name 'a' is not defined
Is there a particular reason why fields in Python have to be defined in this unintuitive fashion, i.e. you would expect to get the value of a field from a getter and you would expect to set a value of a field with a setter. What is the inherent necessity for @propery
?
Why is the following (Java-like) syntax not possible in Python:
class Booz:
a: int
@a.getter
def a(self):
if isinstance(a, int):
return self.a