[Hack][2.2] One way to implement private variables

Nick Mathewson QnickQm at alum.mit.edu
Mon Nov 12 15:25:20 EST 2001


Here's a neat way to hack up private methods and variables in Python
2.2.  

BUGS: 
  -It's not terribly optimized, and there are probably better ways to
   do it.

  -It isn't very paranoid.  For instance, you still circumvent
   access restrictions as easily as:
         Class.privatemember.basic_get(obj)
   This may be considered a feature.

  -It doesn't distinguish between readers and writers.


============================================================
import sys
import types

class ForbiddenAccess(TypeError):
    pass

class private(object):
    __slots__ = ["permittedCode", "basic_get", "basic_set", "basic_del" ]
    def __init__(self, basic, permitted):
	self.basic_set = getattr(basic, "__set__", None)
	self.basic_get = getattr(basic, "__get__", None)
	self.basic_del = getattr(basic, "__del__", None)
	self.permittedCode = {}
	try:
	    it = iter(permitted)
	except TypeError:
	    permitted = [permitted]
	for v in permitted:
	    self.__buildcodeset(v, self.permittedCode)

    def __get__(self, obj,type=None):
	if hash(sys._getframe().f_back.f_code) not in self.permittedCode:
	   raise ForbiddenAccess()
	return self.basic_get(obj,type)

    def __set__(self, obj, val):
	if hash(sys._getframe().f_back.f_code) not in self.permittedCode:
	    raise ForbiddenAccess()
	return self.basic_set(obj, val)

    def __del__(self, obj):
	if hash(sys._getframe().f_back.f_code) not in self.permittedCode:
	    raise ForbiddenAccess()
	return self.basic_del(obj)

    def __buildcodeset(self, obj, codeset):
	if isinstance(obj, types.FunctionType):
	    codeset[hash(obj.func_code)] = 1
	elif isinstance(obj, types.UnboundMethodType):
	    codeset[hash(obj.im_func.func_code)] = 1
	elif isinstance(obj, (type, types.ClassType)):
	    for v in obj.__dict__.values():
		self.__buildcodeset(v, codeset)

if __name__ == '__main__':

    class User(object):
	__slots__ = ["x","y"]
	
	def __init__(self):
	    self.x = 0
	    
        def setX(self, val):
	    self.x = val

	def getX(self):
	    return self.x

    User.x = private(User.x, User)

    u = User()
    print u.getX()
    u.setX(99)
    print u.getX()

    try:
	print u.x, "This should never be reached"
    except ForbiddenAccess:
	pass

    try:
	u.x = 3
	print "This should never be reached."
    except ForbiddenAccess:
	pass

============================================================

"Protected"-left-as-an-exercise-for-the-reader-ly y'rs,

-- 
 Nick Mathewson    <Q nick Q m at alum dot mit dot edu> 
                     Remove Q's to respond.  No spam.



More information about the Python-list mailing list