On Jun 2, 8:14 am, Carl Banks <[EMAIL PROTECTED]> wrote: > Fair enough, but I don't see anything in your example that suggests a > way to discriminate between access from within the class and access > from outside the class, which is the crucial aspect of data hiding.
And, if you want an example of something that does that, how about this metaclass. It creates a class that checks the stack frame to see if the caller was defined in the same class. Issues: Classes are prevented from defining their own __setattr__ and __getattribute__. Classes and subclasses should not use the same names for their private variables. Private attribute access is pretty slow, but that's obvious. Pretty easy to thwart. #---------------------------------- import sys import itertools class PrivateAccessError(Exception): pass class PrivateDataMetaclass(type): def __new__(metacls,name,bases,dct): function = type(lambda x:x) privates = set(dct.get('__private__',())) codes = set() for val in dct.itervalues(): if isinstance(val,function): codes.add(val.func_code) getframe = sys._getframe count = itertools.count def __getattribute__(self,attr): if attr in privates: for i in count(1): code = getframe(i).f_code if code in codes: break if code.co_name != '__getattribute__': raise PrivateAccessError( "attribute '%s' is private" % attr) return super(cls,self).__getattribute__(attr) def __setattr__(self,attr,val): if attr in privates: for i in count(1): code = getframe(i).f_code if code in codes: break if code.co_name != '__setattr__': raise PrivateAccessError( "attribute '%s' is private" % attr) return super(cls,self).__setattr__(attr,val) dct['__getattribute__'] = __getattribute__ dct['__setattr__'] = __setattr__ cls = type.__new__(metacls,name,bases,dct) return cls #---------------------------------- import traceback class A(object): __metaclass__ = PrivateDataMetaclass __private__ = ['internal'] def __init__(self,n): self.internal = n def inc(self): self.internal += 1 def res(self): return self.internal class B(A): __private__ = ['internal2'] def __init__(self,n,m): super(B,self).__init__(n) self.internal2 = m def inc(self): super(B,self).inc() self.internal2 += 2 def res(self): return self.internal2 + super(B,self).res() def bad(self): return self.internal2 + self.internal a = A(1) a.inc() print "Should print 2:" print a.res() print print "Should raise PrivateAccessError:" try: print a.internal except PrivateAccessError: traceback.print_exc() print b = B(1,1) b.inc() print "Should print 5:" print b.res() print print "Should raise PrivateAccessError:" try: print b.internal2 except PrivateAccessError: traceback.print_exc() print print "Should raise PrivateAccessError:" try: print b.bad() except PrivateAccessError: traceback.print_exc() print #---------------------------------- Carl Banks -- http://mail.python.org/mailman/listinfo/python-list