We can use a @property
to construct a getter and setter. This is a short example how we can do this:
class A:
def __init__(self,x):
self.x = x
@property
def x(self):
return self.__x
@x.setter
def x(self, x):
if x < 0:
self.__x = 0
elif x > 100:
self.__x = 100
else:
self.__x = x
My case seems to be more complicated.
class A:
def __init__(self, x):
self.__x = x
self.x1()
self.x2()
self.x3()
def x1(self):
self.__x1 = self.__x + 1
return self.__x1
def x2(self):
self.__x2 = self.__x1 + 2
return self.__x2
def x3(self):
self.__x3 = self.__x2 + 3
return self.__x3
if __name__ == "__main__":
a = A(3)
print(a.x3)
Methods x1
, x2
and x3
are oversimplified. The self.__x3
variable is set only once, when the __init__
method is called. Now, I need a getter method to get self.__x3
by calling a.x3
. How to achieve that in the pythonic way?
Attempting an answer based on the assumption that you want the __x#
variables modified only during __init__
, and never again, but also want the accessors to follow the same code path (possibly because the read is also programmatically complex):
In this case, you can have the implementing function take an additional, defaulted argument. When accessed in attribute form, it will receive the defaulted argument, but if the fget
member of the property is explicitly accessed, it can be called with the non-default argument. A simple example addressing x1
only:
class A:
def __init__(self, x):
self.__x = x
# Access the property itself off the class, bypassing execution,
# then call it directly with the non-default argument
type(self).x1.fget(self, True)
@property
def x1(self, doset=False):
if doset:
self.__x1 = self.__x + 1
return self.__x1
Alternatively, to simplify the usage in __init__
, you can use a separate name for the underlying function vs. the property
to achieve the same effect:
class A:
def __init__(self, x):
self.__x = x
# Call the implementing function directly with the non-default argument
self._x1(True)
# Implementing function named with single underscore prefix to indicate it's
# for internal/protected use only
def _x1(self, doset=False):
if doset:
self.__x1 = self.__x + 1
return self.__x1
# Define property x1 based on x1 for outside use
x1 = property(_x1)
Of course, if you don't have a complicated getter path, then the real solution is to separate _x1
from x1
completely, where _x1
is pure setter helper function for __init__
, and x1
is pure getter:
class A:
def __init__(self, x):
self.__x = x
# Call the init helper
self._init_x1()
# Implementing function named with single underscore prefix to indicate it's
# for internal/protected use only
def _init_x1(self):
self.__x1 = self.__x + 1
@property:
def x1(self):
return self.__x1
To be clear, only the last of these is "Pythonic" in any meaningful sense. The second option has some limited use cases (where you have a function that demands existence, and is highly configurable, but has a reasonable set of defaults that a property
could use), but in that case, it's usually a function that has public utility just like the property
. Option #1 is the least Pythonic, as it's inconvenient to use (needing to elevate to the class type, extract the fget
member, and explicitly pass self
), and makes it quite clear that there is no expected use case outside of __init__
(because it's such a pain to use that no one would bother).