[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