Hi, I had a quick search & didn't find anything _nice_ that produced attributes with really private data, so I came up with a possible solution---for Python 3. (For Python 2 there does seem to be an approach although I'm not keen on it: http://www.builderau.com.au/blogs/byteclub/viewblogpost.htm?p=339270875 )
Here's a standard class with one read-only and one writable property that has a tiny bit of validation. class P: def __init__(self, w): self.w = w @property def r(self): return 5 @property def w(self): return self.__w @w.setter def w(self, value): if value > 0: # Only +ve values allowed self.__w = value else: raise ValueError("'{0}' is not valid for w".format(value)) The read-only property is completely private because it isn't actually stored as such. But if we do dir() on an instance, in addition to 'r' and 'w', we also have '_P__w'. So the writable property's data is easily accessible, and the validation can be got around: >>> p = P(9) >>> p.r, p.w (5, 9) >>> p.w = 43 >>> p.r, p.w (5, 43) >>> p.w = -7 Traceback (most recent call last): ... ValueError: '-7' is not valid for w >>> p._P__w = -7 >>> p.r, p.w (5, -7) Here's a class where I can't think of a way to access the private data and set invalid values. class A: r = Attribute("r", 5) w = Attribute("w", None, lambda self, value: value > 0) def __init__(self, w): self.w = w The Attribute class is a descriptor that takes three arguments: name of attribute, initial value (essential for read-only attributes!), and a validator function (which could be "lambda *a: True" if any value is accepatble). >>> a = A(9) >>> a.r, a.w (5, 9) >>> a.w = 43 >>> a.r, a.w (5, 43) >>> a.w = -7 Traceback (most recent call last): ... ValueError: '-7' is not valid for w If we do a dir(a) the only attributes we get (beyond those from object) are 'r' and 'w', so it shouldn't be possible to get around the validation---at least not easily. Here's a rough & ready implementation of the Attribute class: class Attribute: def __init__(self, name, first_value=None, validator=None): self.__name__ = name hidden_value = first_value self.__getter = lambda self: hidden_value if validator is not None: def set(self, value): if validator(self, value): nonlocal hidden_value hidden_value = value else: raise ValueError("'{0}' is not valid for {1}".format(value, name)) self.__setter = set else: self.__setter = None def __get__(self, instance, owner=None): if instance is None: return self return self.__getter(instance) def __set__(self, instance, value): if self.__setter is None: raise AttributeError("'{0}' is read-only".format( self.__name__)) return self.__setter(instance, value) The key to making the attribute data private is that it is held as part of a closure's state. Notice that nonlocal is needed, so you need Python 3. -- Mark Summerfield, Qtrac Ltd, www.qtrac.eu C++, Python, Qt, PyQt - training and consultancy "Programming in Python 3" - ISBN 0137129297 -- http://mail.python.org/mailman/listinfo/python-list