On 8 May, 09:52, Carl Banks <pavlovevide...@gmail.com> wrote: > On May 7, 11:37 pm, MarkSummerfield<l...@qtrac.plus.com> wrote: > > > > > 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. > > Ok, I'll bite. > > A.w = -7 > > A.__class__ = A_without_validation > a.w = -7 > > Attribute.__set__ = function_that_ignores_validation > a.w = -7
I don't see how that can work? Sure you could replace the __set__ method, or the Attribute.__setter method. But neither can actually change the hidden_value because AFAIK that only exists within the scope of a closure and so isn't accesssible. (Well, maybe if you started using the inspect module you'd find it.) > I am not opposed to adding a little well-considered protection to some > attributes where mistakes are prone to happen and/or dangerous, but it > is futile to try to stop access entirely. There's just too many back > doors. Sure, but I like the fact that there is no "shadow" attribute, so just "w" not "w" _and_ "_A__w". > I would suggest that there really isn't much point in anything more > complex than your first solution, which was to validate with > properties and to store the value in a separate attribute. > Respectable programmers won't lightly bypass your validation if they > see that you've taken steps to enforce it. OTOH, once a programmer, > respectable or not, decides to override your protection, they are not > likely to be stopped by something more complex. So there is no point > in making it more complex. > > Carl Banks I think that's a fair viewpoint, but I still like the idea of there being no _A__w available for property w. -- 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