I'm relatively new to Python so I hope I haven't missed something, but here goes...
I'm trying to write a Python module, and I'd like to create a class with a "private" attribute that can (or maybe 'should') only be modified through one or more functions within the module. This is in an effort to make the module more robust, since setting of this attribute outside of these functions could lead to unwanted behaviour. For example, I might have:
- A class that stores x and y values for a scatter plot,
Data - A function to read x and y values from a file and store them in the class,
read() - A function to plot them,
plot()
In this case, I would prefer if the user wasn't able to do something like this:
data = Data()
read("file.csv", data)
data.x = [0, 3, 2, 6, 1]
plot(data)
I realise that adding a single leading underscore to the name indicates to the user that the attribute should not be changed, i.e. rename to _x and add a property decorator so that the user can access the value without feeling guilty. However, what if I wanted to add a setter property as well:
class Data(object):
_x = []
_y = []
@property
def x(self):
return self._x
@x.setter
def x(self, value):
# Do something with value
self._x = value
I'm now in the same position as I was before - the user can no longer directly access the attribute _x, but they can still set it using:
data.x = [0, 3, 2, 6, 1]
Ideally I'd rename the property function definitions to _x(), but this leads to confusion about what self._x actually means (depending on the order in which they are declared, this seems to result in either the setter being called recursively or the setter being ignored in favour of the attribute).
A couple of solutions I can think of:
- Add a double leading underscore to the attribute,
__x, so that the name becomes mangled and does not get confused with the setter function. As I understand it, this should be reserved for attributes that a class does not wish to share with possible subclasses, so I'm not sure if this is a legitimate use. - Rename the attribute, e.g.
_x_stored. While this solves the problem completely, it makes the code harder to read and introduces naming convention issues - which attributes do I rename? just the ones that are relevant? just the ones that have properties? just the ones within this class?
Are either of the above solutions applicable? And if not, is there a better way to solve this problem?
A few points brought up in the comments:
- I want to retain the extra logic that the setter property gives me - the
# Do something with valuesection in the above example - so internally setting the attribute through direct access ofself._xdoesn't solve the problem. - Removing the setter property and creating a separate function
_set_x()does solve the problem, but is not a very neat solution since it allows setting of_xin two different ways - either by calling that function or through direct access ofself._x. I'd then have to keep track of which attributes should be set by their own (non-property) setter function and which should be modified through direct access. I'd probably rather use one of the solutions I suggested above, because even though they make a mess of the naming conventions within the class they are at least consistent in their use outside of the class, i.e. they all use the syntactical sugar of properties. If there's no way of doing this in a neater way then I guess I just have to choose the one that causes the least disruption.
interpolate()function that needs to be able to set the x and y values._xand_y._setx()that is used internally if you want to capture your extra logic when setting. I dont think the other option complexities are worth the limited syntactical sugar.