Decorator to inject function into __call__ of a class

Jon Clements joncle at googlemail.com
Sat Mar 13 14:02:44 EST 2010


On 13 Mar, 17:42, Jack Diederich <jackd... at gmail.com> wrote:
> On Sat, Mar 13, 2010 at 12:10 PM, Jon Clements <jon... at googlemail.com> wrote:
> > On 13 Mar, 16:42, Jack Diederich <jackd... at gmail.com> wrote:
> >> On Sat, Mar 13, 2010 at 11:19 AM, Jon Clements <jon... at googlemail.com> wrote:
> >> > This is semi-experimental and I'd appreciate opinions of whether it's
> >> > the correct design approach or not. It seems like a good idea, but it
> >> > doesn't mean it is.
>
> >> > I have a class 'A', this provides standard support functions and
> >> > exception handling.
> >> > I have 'B' and 'C' which specialise upon 'A'
>
> >> > What I'd like to achieve is something similar to:
>
> >> > @inject(B):
> >> >  def some_function(a, b):
> >> >     pass # something useful
>
> >> > The name 'some_function' is completely redundant -- don't need it,
> >> > don't actually care about the function afterwards, as long as it
> >> > becomes a __call__ of a 'B' *instance*.
>
> >> > I've basically got a huge list of functions, which need to be the
> >> > callable method of an object, and possibly at run-time, so I don't
> >> > want to do:
>
> >> > class Something(B):
> >> >    def __call__(self, etc.. etc...):
> >> >         pass # do something
>
> >> > I've got as far as type(somename, (B,), {}) -- do I then __init__ or
> >> > __new__ the object or...
>
> >> > In short, the function should be the __call__ method of an object that
> >> > is already __init__'d with the function arguments -- so that when the
> >> > object is called, I get the result of the the function (based on the
> >> > objects values).
>
> >> I'm not sure exactly what you are asking for, but if what you want is
> >> a bunch of different objects that vary only by their class's __call__
> >> you could do it with a function that returns a new class based on A
> >> but with a new __call__:
>
> >> def make_new_call_class(base_class, call_func):
> >>   class NewClass(base_class):
> >>     def __call__(self, *args, **kw):
> >>       return call_func(self, *args, *kw)
> >>   return NewClass
>
> >> or the return could even be NewClass() [return an instance] if this is
> >> a one off.
>
> >> That said, I'm not really sure what this behavior is good for.
>
> >> -Jack
>
> > Cheers Jack for the response.
>
> > The behaviour is to not derive from a class, but rather allow
> > the decorators to do so... so I would like to iterate over
> > a list of functions (don't care what they're called) and then
> > inject the function as a method. If needs be at run-time.
>
> > Say I have 1000 functions (okay, admittedly over quoted), but
> > I don't want every programmer to inherit from 'B' or 'C', but
> > to 'inject'. So the idea is that classes are pre-defined, have
> > predictable behaviour, *except* the __call__ is different.
>
> > You are correct in this. Why do I want that behaviour? ->
>
> > - It's easier, no inheriting from a class, when needs not.
> > - Some integrity (anyone can define a function and 'inject' to the
> > Management class)
> > - Easier maintainability - maybe :)
>
> > for i in function_list:
> >    i = inject(function_list)
>
> > At the end of the day:
> > def blah(x, y, z):
> >   pass
>
> > That should be the callable of the object.
>
> I'm still not sure why you are trying to do this, but you can do it
> with delegation.  Have the parent class's __call__ look for an
> instance attribute named call_this and then call it, ex/
>
> class A():
>   def __call__(self, *args, **kw):
>     self.call_this(*args, **kw)  # we grab this off the instance
>
> ob = A()
> def my_func(*stuff): pass
> ob.call_this = my_func
>
> -Jack

Jack, thanks very much for your replies -- hugely appreciated.

I was delayed by the missus calling me for dinner - I'd forgotten
we had a stew going in the slow cooker, and she can't make
dumplings to save her life :)

If I can re-explain slightly, say I have a class 'compute':

class Compute(object):
    def __init__(self, something):
        self.something = something
    # misc other methods here.....

then...

class ComputeAdd(Compute):
    pass

If I do,

@inject
def ComputeAdd(fst, snd):
    return fst + snd

The end result should be a new class called ComputeAdd __init__'d with
fst and snd,
which when called, returns fst + snd.

Hope that makes sense.

Cheers,

Jon.




More information about the Python-list mailing list