Method behavior for user-created class instances

Discussion in 'Python' started by crazychimp132@gmail.com, Jul 15, 2008.

  1. Guest

    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.
     
    , Jul 15, 2008
    #1
    1. Advertising

  2. Guest

    On Jul 14, 9:04 pm, Larry Bates <`> wrote:
    > 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__().
     
    , Jul 15, 2008
    #2
    1. Advertising

  3. Guest

    On 15 juil, 01:24, 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.


    You need to implement the descriptor protocol the same way the
    function type do.

    import types

    class Foo(object):
    def __call__(self, instance):
    print "%s - %s" % (self, instance)

    def __get__(self, instance, cls):
    return types.MethodType(self, instance, cls)

    class Bar(object):
    foo = Foo()

    b = Bar()
    b.foo()


    > 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.


    Extending types.FunctionType doesn't work OOTB (there's some
    incompatibility wrt/ metaclasses)
     
    , Jul 15, 2008
    #3
  4. Guest

    On Jul 15, 9:53 am, ""
    <> wrote:
    > On 15 juil, 01:24, 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.

    >
    > You need to implement the descriptor protocol the same way the
    > function type do.
    >
    > import types
    >
    > class Foo(object):
    > def __call__(self, instance):
    > print "%s - %s" % (self, instance)
    >
    > def __get__(self, instance, cls):
    > return types.MethodType(self, instance, cls)
    >
    > class Bar(object):
    > foo = Foo()
    >
    > b = Bar()
    > b.foo()
    >
    > > 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.

    >
    > Extending types.FunctionType doesn't work OOTB (there's some
    > incompatibility wrt/ metaclasses)


    Thanks, this got me started in writing it for 3.0. There are no more
    unbound methods in 3.0, so a check for whether instance is None is
    necessary to give the right behavior. Here is the final implementation
    I came up with:

    from abc import ABCMeta, abstractmethod
    from functools import update_wrapper
    from types import MethodType

    class decorator(metaclass = ABCMeta):
    def __init__(self, function):
    update_wrapper(self, function)
    self.function = function

    def __get__(self, instance, cls):
    if instance is None:
    return self
    return MethodType(self, instance)

    @abstractmethod
    def __call__(): pass

    To use it, write a class that inherits decorator and overrides
    __call__, probably doing something with self.function.
     
    , Jul 15, 2008
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John Wohlbier
    Replies:
    2
    Views:
    391
    Josiah Carlson
    Feb 22, 2004
  2. Jeremy Bowers

    finding name of instances created

    Jeremy Bowers, Jan 21, 2005, in forum: Python
    Replies:
    29
    Views:
    632
    =?iso-8859-1?B?QW5kcuk=?=
    Jan 24, 2005
  3. newseater

    changing how instances are "created"

    newseater, Jun 13, 2005, in forum: Python
    Replies:
    7
    Views:
    315
    John Roth
    Jun 13, 2005
  4. Replies:
    8
    Views:
    482
    James Stroud
    Jan 29, 2009
  5. Phrogz
    Replies:
    1
    Views:
    114
    Phrogz
    Dec 24, 2006
Loading...

Share This Page