What *instance* called me & proxy methods
Carlos Alberto Reis Ribeiro
cribeiro at mail.inet.com.br
Wed Mar 28 11:57:43 EST 2001
I've seen some talk on how to get the name of the caller. I got a related
problem to solve, only slightly more complicated.
Can I know what *instance* called a method? I'm not talking about "self"
here, because we *can* call a method using other techniques, such as
copying the instance method pointer directly:
>>> class myclass:
... def hello(self):
... print "hi! I'm ", self
>>> class myproxy:
... pass
>>> a = myclass()
>>> a.hello()
hi! I'm <__main__.myclass instance at 015093EC>
>>> m = a.hello
>>> p = myproxy()
>>> p.m = m
>>> p.m()
hi! I'm <__main__.myclass instance at 015093EC>
In both cases, hello() received the same value as the self parameter. This
is exactly what I need; in fact, the im_self attribute of the instance
method stores the pointer to self, which explains this behavior. However, I
would also like to have some information to differentiate between these two
calls. My goal is to implement some security checking as part of my
proxy/adapter module [1]. I have already tried some simple minded
approaches (too many to list here), so far with no success.
The best solution the I have thought so far can be implemented as a Python
extension - if I manage to put my Linux box up and running (I'm gcc-less
right now :-).
1) Implement a new object called 'ProxyMethod', derived of 'instance
method', with the following differences:
* It does not make the im_* attributes visible to the outside
world;
* It stores a read-only attribute to the proxy that 'owns' the
ProxyMethod.
2) The 'ProxyMethod' constructor would take a instance method and
build the proxy method from it.
3) The information about the proxy would need to be stored somewhere
in the call stack. I dont know if it is possible without changing
some of the Python internals.
4) The runtime semantics of the 'ProxyMethod' would be about the
same as the ones of the instance method - just a direct call,
without any extra intermediation.
I would like to know what the community thinks about turning this into a
PEP. Maybe we can find a simpler solution, or it's better to keep this as a
module outside the distribution.
For now I have a very simple Python implementation. It's far from perfect,
and it has some undesirable side effects because it is not completely
transparent, and it needs some intermediate processing. The only way that I
found to signal to the proxied object about the existence of the proxy was
to create a temporary "proxy" attribute (see point (3) above). However, it
serves it purpose as a proof-of-concept:
----------------------------------------------------------------------
TEST RESULT
>>> n = NuclearArsenal()
>>> n.NuclearAttack("NY")
Only the proxy can order the attack
>>> p = Proxy()
>>> p.attack = ProxyMethod(n.NuclearAttack, p)
>>> p.attack("NY")
Boooom! NY destroyed
----------------------------------------------------------------------
CODE
""" ProxyMethod proof-of-concept
(c) 2001 Carlos Ribeiro - cribeiro at mail.inet.com.br
Released in public domain for use "as-is"
"""
from types import *
class Proxy:
pass
class ProxyMethod:
def __init__(self, im, p):
if type(im) != MethodType:
raise "A proxy needs a method"
if p.__class__ != Proxy:
raise "A proxy method is bounded to a proxy"
self.im = im
self.p = p
def __call__(self, *a):
# set a flag inside the target instance
setattr(self.im.im_self, 'proxy', self.p)
# do the call
self.im(*a)
# clear the flag
delattr(self.im.im_self, 'proxy')
class NuclearArsenal:
def NuclearAttack(self, city):
if getattr(self, 'proxy', None):
# called through the proxy
print "Boooom! %s destroyed" % (city)
else:
print "Only the proxy can order the attack"
----------------------------------------------------------------------
Carlos Ribeiro
More information about the Python-list
mailing list