Method behavior for user-created class instances

crazychimp132 at gmail.com crazychimp132 at gmail.com
Mon Jul 14 23:21:37 EDT 2008


On Jul 14, 9:04 pm, Larry Bates <larry.ba... at websafe.com`> wrote:
> crazychimp... at gmail.com wrote:
> > Greetings.
>
> > I am looking for a way to achieve method behavior for a class I
> > created. That is, it has a __call__ method,  so can be called like a
> > function. But I also want it to be treated as a method when it appears
> > in a class body.
>
> > Eg.
>
> > class foo:
> >     def __call__(self, inst): pass
>
> > class bar:
> >     meth = foo()
>
> > such that bar().meth() will not raise an exception for too few
> > arguments (because the inst argument in foo.__call__ is implicitly set
> > to the bar instance). I know this has to do with writing the __get__
> > method of foo, but I am wondering if there is perhaps some class I can
> > just inherit from to get the proper __get__, which behaves identically
> > to that of regular Python functions. The need for this arises out of
> > the implementation of a function decorator as a class.
>
> > Thanks.
>
> While it is not clear "why" you would want this, I believe this works.
> If not, take a look at staticmethods or classmethods, they might work for you.
>
>  >>> class foo(object):
> ...     def __call__(self, inst):
> ...         print "foo.__call__", inst
> ...
>
>  >>> class bar:
> ...     def __init__(self):
> ...         self.foo = foo()
> ...         self.meth = self.foo.__call__
> ...
>  >>> b = bar()
>  >>> b.meth(1)
> foo.__call__ 1
>
> -Larry

This doesn't work for me. I have a class which is used to decorate
functions, returning a callable object in the place of the original
function. So, instances of this class must be able to be used anywhere
a function would be used, and this means getting method behavior when
it is used in a class body.

A working implementation would be (in 3.0):

from functools import partial
from abc import ABCMeta, abstractmethod

class method_behavior(metaclass = ABCMeta):
    def __get__(self, instance, owner):
        if instance is None:
            return self.__call__
        return partial(self.__call__, instance)

    @abstractmethod
    def __call__(): pass

Then, any decorator class can inherit from it:

class foo(method_behavior):
    def __init__(self, func):
        self.func = func
    def __call__(self, *args, **kwds):
        print("calling decorated func")
        return self.func(*args, **kwds)

Then, we can decorate a function with foo (via @foo) and it will work
either inside a class body or outside, it works everywhere an
undecorated function would work, eg.:

@foo
def bar():
    print('bar')

class baz:
    @foo
    def bar(self):
        print('bar')

What I am asking is whether there is a way to directly inherit method
behavior, instead of inexactly rewriting it as I did in
method_behavior.__get__().



More information about the Python-list mailing list