"Private" attribute properties in Python

Solution 1:

If you want to discourage users from changing a property, but want it to be clear that they can read it, I'd use @property without providing a setter, similar to what you described earlier:

class Data(object):
    def __init__(self):
       self._x = []
       self._y = []

    @property 
    def x(self):
        return self._x

    @property 
    def y(self):
        return self._x

I know you mention "What if I wanted to add a setter to the property?", but I guess I would counter that with: Why add the setter if you don't want your clients to be able to set the property? Internally, you can access self._x directly.

As for a client directly accessing _x or _y, any variable with an '_' prefix is understood to be "private" in Python, so you should trust your clients to obey that. If they don't obey that, and end up screwing things up, that's their own fault. This kind of mindset is counter to a many other languages (C++, Java, etc.) where keeping data private is considered very important, but Python's culture is just different in this regard.

Edit

One other note, since your private properties in this particular case are lists, which are mutable (unlike strings or ints, which are immutable), a client could end up changing them somewhat accidentally:

>>> d = Data()
>>> print d.x
['1', '2']
>>> l = d.x
>>> print l
['1', '2']
>>> l.append("3")
>>> print d.x
['1', '2', '3']  # Oops!

If you want to avoid this, you'd need your property to return a copy of the list:

@property
def x(self):
    return list(self._x)