What *instance* called me & proxy methods

Carlos Alberto Reis Ribeiro cribeiro at mail.inet.com.br
Wed Mar 28 18:57:43 CEST 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