Method behavior for user-created class instances

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • crazychimp132@gmail.com

    Method behavior for user-created class instances

    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.
  • Larry Bates

    #2
    Re: Method behavior for user-created class instances

    crazychimp132@g mail.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

    Comment

    • crazychimp132@gmail.com

      #3
      Re: Method behavior for user-created class instances

      On Jul 14, 9:04 pm, Larry Bates <larry.ba...@we bsafe.com`wrote :
      crazychimp...@g mail.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_beha vior):
      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__().

      Comment

      • bruno.desthuilliers@gmail.com

        #4
        Re: Method behavior for user-created class instances

        On 15 juil, 01:24, crazychimp...@g mail.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.
        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.MethodTyp e(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.FunctionT ype doesn't work OOTB (there's some
        incompatibility wrt/ metaclasses)


        Comment

        • crazychimp132@gmail.com

          #5
          Re: Method behavior for user-created class instances

          On Jul 15, 9:53 am, "bruno.desthuil li...@gmail.com "
          <bruno.desthuil li...@gmail.com wrote:
          On 15 juil, 01:24, crazychimp...@g mail.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.
          >
          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.MethodTyp e(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.FunctionT ype 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(metac lass = 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.

          Comment

          Working...