transparent proxy object

Irmen de Jong irmen at -NOSPAM-REMOVETHIS-xs4all.nl
Wed Feb 26 17:41:09 EST 2003


Alex A. Naanou wrote:
> Task:
>   "transparently" intercept/cache all calls to the object, all its
> attributes and sub-objects while maintaining full object
> functionality.
> 
> The Answer:
>   here is the answer I came up with, though it fits the task
> semanticly and I like how it works in concept, the application is
> rather time-critical thus this code does not fit the job...
>   does any one have an idea how to implement something with the same
> semantics but more efficiently (I'm intrested in a pure Python
> solution, not a C/C++ extention type)??      ...Thanks.
> 

What about the code below?
I snipped it from Pyro and stripped it a bit.
Didn't do any comparison with your code, although yours
looks a lot more complex than this one...

Irmen de Jong




-----


	
class DynamicProxy:
	def __init__(self, proxiedObject):
		# first set the list of 'local' attrs for __setattr__
		self.__dict__["_local_attrs"] = ("_local_attrs", "_name", "_proxiedObject" )
		self._proxiedObject=proxiedObject
		self._name=[]
	def _r_ga(self, attr, value=0):
		if value: self._name.append("_r_ga")
		else: self._name.append("_r_ha")
		return self.__invokeOriginal__(attr)
	def findattr(self, attr):
		return self._r_ga(attr)
	def __setattr__(self, attr, value):
		if attr in self.__dict__["_local_attrs"]:
			self.__dict__[attr]=value
		else:
			result = self.findattr(attr)
			if result==2: # attribute
				self._name.append("_r_sa")
				return self.__invokeOriginal__(attr,value)
			else:
				raise AttributeError('not an attribute')
	def __getattr__(self, attr):
		# allows it to be safely pickeled
		if attr != "__getinitargs__":
			result=self.findattr(attr)
			if result==1: # method
				self._name.append(attr)
				return self.__invokeOriginal__
			elif result:
				return self._r_ga(attr, 1)
		raise AttributeError()
	def __invokeOriginal__(self, *vargs, **kargs):
		methodName=self._name.pop()
		if methodName=="_r_ha":
			try:
				attr = getattr(self._proxiedObject ,vargs[0])
				if type(attr) in (UnboundMethodType, MethodType, BuiltinMethodType):
					return 1 # method
			except:
				pass
			return 2 # attribute
		elif methodName=="_r_ga":
			return getattr(self._proxiedObject, vargs[0])
		elif methodName=="_r_sa":
			return setattr(self._proxiedObject, vargs[0], vargs[1])
		method = getattr(self._proxiedObject, methodName )
		return apply(method, vargs, kargs)
		

# test

class Test:
	def __init__(self):
		print "init from test"
		self.attribute = 42
	def method(self, arg):
		print "method in test, arg=",arg
		return "result from test method!!!"
	def setAttribute(self, value):
		self.attribute=value	

object = Test()
proxy = DynamicProxy(object)

print "Calling method:"
print proxy.method("the arguments")
print "Printing attribute:"
print proxy.attribute
print "Setting attribute with method"
proxy.setAttribute(99)
print "Printing attribute:"
print proxy.attribute
print "Setting attribute directly"
proxy.attribute=555
print "Printing attribute:"
print proxy.attribute
print "Printing original attribute:"
print object.attribute





More information about the Python-list mailing list