Metaclass with name overloading.

Bengt Richter bokr at oz.net
Mon Sep 27 16:56:04 EDT 2004


On Mon, 27 Sep 2004 19:11:14 +0200, aleaxit at yahoo.com (Alex Martelli) wrote:

>Thomas Heller <theller at python.net> wrote:
>   ...
>> It won't work for ordinary attributes, but for overloading methods you
>> should be able to play some tricks with decorators and sys._getframe().
>
>Great idea... love it!!!  To clarify it a bit for people who may not be
>as familiar with internals as Mr Heller...: a decorator 'sees' the
>method it's decorating "at once", so it doesn't matter if that method's
>name later gets trampled upon... as long as the decorator can stash the
>original away somewhere, and the frame in which the class body is
>executing is just the right 'somewhere'.
>
>A code snippet may be clearer than words...:
>
>import sys, itertools
>
>_ignore_method = object()
>
>def overloaded(f):
>    d = sys._getframe(1).f_locals
>    n = '__overloaded__%s__%%d' % f.func_name
>    for i in itertools.count():
>        nx = n % i
>        if nx in d: continue
>        d[nx] = f
>        break
>    return _ignore_method
>
>class blop:
>    @ overloaded
>    def f(self): return 'first f'
>    @ overloaded
>    def f(self): return 'second f'
>
>print blop.__dict__
>
>
>so, class blop doesn't really have an 'f' (it does have it in the
>__dict__, but it's a dummy '_ignore_method' entry with a suitable custom
>metaclass would easily prune!-) but has __overloaded__f__0 and
>__overloaded__f__1 methods (which, again, a suitable custom metaclass
>could do whatever wonders with!-).
>
>For overload purposes, you might have the decorator actually take as
>arguments some _types_ and record them so that the metaclass can arrange
>for the dispatching based on actual-argument types...
>
>If you bletch at having to decorate each overloaded version with
>'@overloaded', consider C# basically requires that "just BECAUSE",
>without even having a good excuse such as "we need to do it that way due
>to Python's semantics"...;-)
>
If there were a way to make a local bare name access work like a property
or other descriptor, by designating such names suitably, then def f...
could trigger the setter of an f property and that could do whatever.

It might be interesting for a function closure variables also, but here
we are talking about class bodies. Here is a straw man:

    class blop:
        localdesc:
            f = property(fget, fset)
        def f(self): return 'first f'
        def f(self): return 'second f'

This effectively considers the local namespace as the attribute name space
of _something_, presumably an internal instance of some synthesized Localspace class,
let's say localspace = LocalspaceType()() -- IOW a fresh class as well as its instance,
so as to cut off base class searching and not to have surprising sharing.
Optimization is for later ;-)

The localdesc suite would cause assignment to be via type(localspace).__dict__.__setitem__
whereas normal local names would be evaluated by get/setattr(localspace, barename) and
thus trigger descriptors if present. Note that all bindings including from
def and class as well as ordinary variables could be intercepted by descriptors.

sys._getframe(level).f_locals would presumably be a special proxy object instead of a dict
when there is a localdesc: suite in the body, so that it could decide whether names
are descriptors or ordinary.  Otherwise it could remain the usual dict and not get
a performance hit, I suppose.

Regards,
Bengt Richter



More information about the Python-list mailing list