Metaclasses vs. standard Python reflection?

Robin Becker robin at jessikat.fsnet.co.uk
Sat May 3 15:58:04 EDT 2003


In article <2iUsa.66359$K35.1822304 at news2.tin.it>, Alex Martelli <aleax at aleax.it>
writes
><posted & mailed>
>
>Robin Becker wrote:
>
>> .....when trying to intercept/hook instance __setattr__ magic I find it
>> extremely hard with mundane python.
.......
>a.c = 3 may trigger a.__class__.__setattr__(a, 'c', 3), but doesn't
>go looking for a per-instance a.__setattr__.  More generally, do not
>rely on per-instance special methods, as throughout the new-style
>object model it's only special methods that live in *classes* that
>participate in operations, NOT those set specifically on instances.
>
>
.......
>o be done far more simply of course:
>
>def hook_setattr(inst):
>    class hooker(inst.__class__):
>        def __setattr__(*args):
>            print 'hook(%r,%r,%r)' % args
>    hooker.__name__ = inst.__class__.__name__
>    inst.__class__ = hooker
>
>class A: pass
>a = A()
>hook_setattr(a)
>a.y = 3
>
>class B(object): pass
>b = B()
>hook_setattr(b)
>b.z = 4
>
>This approach has the advantage of working for both classic AND
>newstyle classes, too -- sometimes a substantial plus!
>
>

yes indeed that is what I'm intending. Dynamic messing with attribute setting.

.......
>therein, and a __setattr__ such as:
>
>    def __setattr__(self, attname, attval):
>        hook = self.hooker.get(self)
>        if hook is not None: return hook(self, attname, attval)
>        self.__dict__[attname] = attval   # or whatever
>
>but unless most instances of A are hooked most of the time, this
>threatens to be a very heavyweight approach, slowing down every
>attribute-setting on every unhooked instance quite significantly.
>
>What exactly IS the problem you see with the hook_setattr approach?
>
>
>Alex
....this is very similar to what I'm actually trying to do.

We already have an attribute checking mechanism. The need is to create proxy
attributes in a tree structure that hide attributes  further down the tree

ie a has components b and c, but rather than set a.b.font, a.c.font I want to create
a single a.font that dynamically sets both. In addition I wish to hide the original
attributes from casual inspection/setting. The hiding part
requires dynamically changing the way the attributes are controlled.

The anonymous class idea is great, but it's I find it
difficult without dynamic scopes to pass in the old __setattr__ if any.
I want to use something like

def _addHook(obj,hook):
        if not hasattr(obj,'__proxy__setattr__'):
                C = obj.__class__
                D={}
                D['__proxy__setattr__']=1
                D['__setattr__'] = lambda self,k,v,osa=getattr(obj,\
                   '__setattr__',None),hook=hook: hook(self,k,v,osa)
                import new
                obj.__class__=new.classobj(C.__name__,(C,)+C.__bases__,D)

where the hook function takes a 4'th argument representing a possible existing
__setattr__.

Perhaps I misunderstand class scopes and you can do this better in 1.5.2.

I keep thinking it should be possible to do

class _HOOK(C):
        __proxy__setattr__ = 1

_HOOK.__setattr__ = lambda.......hook(self,k,v,osa)
_HOOK.__name__ = C.__name__

but am unsure how this plays in new style/old style etc. 
-- 
Robin Becker




More information about the Python-list mailing list