Metaclass with name overloading.
Lenard Lindstrom
len-1 at telus.net
Mon Sep 27 17:23:14 EDT 2004
Carlos Ribeiro <carribeiro at gmail.com> writes:
> On Mon, 27 Sep 2004 19:11:14 +0200, Alex Martelli <aleaxit at yahoo.com> wrote:
> > 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!-).
>
> The decorator could play it safe, and at the same time, return
> something like the original poster expects. Upon decoration the
> following would happen:
>
> 1) store the newly declared object in the list __overloaded__<$name>.
>
> 2) return a new object (to be bound to the <$name>), where
> <$name>.__call__ would return __overloaded__<$name>[-1]; and
> f.__iter__ would return an iterator for all declaration in the order
> they appear.
>
> I did it as follows; it _almost_ works (which really means it's
> broken), because there's a catch that I was not able to solve:
>
> ------------
> import sys, itertools
>
> class OverloadedFunction:
> def __init__(self):
> self.overload_list = []
> def __iter__(self):
> for item in self.overload_list:
> yield item
> def __getitem__(self, index):
> return self.overload_list[index]
> def __call__(self, *args, **kw):
> return self.overload_list[-1](*args, **kw)
> def append(self, f):
> self.overload_list.append(f)
>
> def overloaded(f):
> d = sys._getframe(1).f_locals
> n = '__overloaded__%s' % f.func_name
> #ofl = getattr(d, n, OverloadedFunction())
> if n in d:
> print "achou"
> ofl = d[n]
> else:
> print "não achou"
> ofl = OverloadedFunction()
> print "<",ofl.overload_list,">", d, n
> ofl.append(f)
> d[n] = ofl
> return ofl
>
> class blop:
> def f(self): return 'first f'
> f = overloaded(f)
>
> def f(self): return 'second f'
> f = overloaded(f)
>
> print blop.__dict__
> # there's a catch -- methods were not bound to the instance
> # so I need to pass the 'self' parameter manually
> b = blop()
> print blop.f(b)
> print blop.f[0](b)
> print blop.f[1](b)
>
>
> The problem is that the methods were not bound to the instance. Adding
> individual names to each method won't work, because it'll not bind the
> references stored in the overload_list. I thought about using a
> closure or curry type of solution, but that's something that I still
> don't understand very well. Any tips?
>
Here is my take on decorator overloaded. I implement OverloadedFunction
as a descriptor. It supports method binding.
import sys
class OverloadedFunction(object):
class BoundMethod:
def __init__(self, functions, instance, owner):
self.bm_functions = functions
self.bm_instance = instance
self.bm_owner = owner
def __getitem__(self, index):
return self.bm_functions[index].__get__(self.bm_instance,
self.bm_owner)
def __init__(self):
self.of_functions = []
def addFunction(self, func):
self.of_functions.append(func)
def __get__(self, instance, owner):
return self.BoundMethod(self.of_functions,
instance,
owner)
def overloaded(func):
try:
olf = sys._getframe(1).f_locals[func.__name__]
except KeyError:
olf = OverloadedFunction()
olf.addFunction(func)
return olf
# Test case:
class blob:
def __init__(self, member):
self.member = member
@overloaded
def f(self):
return "f 0: member=%s" % self.member
@overloaded
def f(self, s):
return "f 1: member=%s, s=%s" % (self.member, s)
b=blob("XXX")
print b.f[0]()
print b.f[1]("Yet another f")
---- Output ---
f 0: member=XXX
f 1: member=XXX, s=Yet another f
Lenard Lindstrom
<len-l at telus.net>
More information about the Python-list
mailing list