Intercept methods/raise exception

Gordon McMillan gmcm at hypernet.com
Fri Jul 21 13:23:24 EDT 2000


Thomas Weholt wrote:

>On 20 Jul 2000 23:55:14 GMT, gmcm at hypernet.com (Gordon McMillan)
>wrote:

[proxy class]

>Ok, it seems to work, allthough only if I access methods. Accessing
>simple values like ints and strings directly only traps that value,
>not the attribute name. 

Sure it does. Both __getattr__ and __setattr__ have the name of the 
attribute - it's an argument.

>And, most importantly, how can I make my objects behave like the ones
>used thru a proxy, *without* putting them into one? is it possible? I
>mean, I just want to avoid have to declare one instance, and then
>stuff it into another new instance. Can it be done in one big swoop?

Two ways. The sane way:
 (I'll assume your class is class Fiddle. Now rename it to _Fiddle.)

 def Fiddle(*args, **kwargs):
   obj = apply(_Fiddle, args, kwargs)
   return Proxy(obj)

 Your users will never know what hit them.

The insane way is to take Demo/metaclasses/Trace.py (from the source 
distribution) and modify it to suit your needs. You might know what hit 
you, but that's about all you'll know.

>Anyway, where can I read up on stuff like this? Proxy, nifty object
>handling. Any hints?

The docs (the very early sections of the library reference, and scattered 
thru the language ref) actually explain pretty well how this stuff works. 
They just never give much of a hint what you can do with it. For that, you 
need a madman (Mark Hammond, Tim Peters, Don Beaudry, Aaron Watters, Jim 
Fulton, me).

The single most elegant example of utter depravity is Aaron Watters' 
FreeTerm.py. Clipped from a posting:

#courtesy of Aaron Watters (a posting dated 1997/05/01)

class freeterm:
    def __init__(self, name):
        self.__myname__ = name
    def __getattr__(self, name):
        return attrterm(self, name)
    def __repr__(self):
        return str(self.__myname__)
    def __str__(self):
        return `self`
    def __call__(self, *args, **kargs):
        return callterm(self, args, kargs)
    def __coerce__(a,b):
        return (a,b)
    def __cmp__(a,b):
        return id(a) - id(b)
        
class attrterm(freeterm):
    def __init__(self, thing, attname):
        #print thing, ".", attname
        self.__attname__ = attname
        freeterm.__init__(self, thing)
    def __repr__(self):
        #return "(%s).%s" % (str(self.__myname__), self.__attname__)
        return "%s.%s" % (str(self.__myname__), self.__attname__)
        
import string

class callterm(freeterm):
    def __init__(self, fn, args, kargs):
        self.__myargs__ = args
        self.__kargs__ = kargs
        self.__fn__ = fn
        freeterm.__init__(self, fn)
    def __repr__(self):
        strargs = map(str, self.__myargs__)
        for (key, value) in self.__kargs__.items():
            item = key + "=" + `value`
            strargs.append(item)
        arglist = string.joinfields(strargs, ", ")
        args = "(%s)" % arglist
        return `self.__fn__` + args
        
def test():
    [a,b,c,d,e] = map(freeterm, "abcde")
    print a+b*c
    print a*b+c
    print a.open(d)+e
    print a.this(c).that(e.x)+d
    print (a<<b).grep(d-e)>>c
    print a(d**e, key=b-c)

that'll-teach-ya-<evil-laughter>-ly y'rs



More information about the Python-list mailing list