0

I'm trying to use a function object as a method for a different class (via decorator), but instance binding isn't automatic. Of course, it makes sense that this shouldn't be automatic:

def decorator(method):
   return Functor(method)

class Functor:
   def __init__(self, decorated):
      self.decorated = decorated

   def __call__(self, instance, *args, **kwargs):
      print(f"Calling on {instance = } with {args = }, {kwargs = }")
      self.decorated(instance, *args, **kwargs) 

class SomeClass:
   @decorator
   def some_method(self, a, b):
      print(f"In some method with {a = }, {b = }")

instance = SomeClass()
## I want this to work...
# instance.some_method(1, 2)

## This works, but I want binding like the above one...
instance.some_method(instance, 1, 2)

How do I make the above snippet work with instance.some_method(1, 2)?

I think the answer lies with descriptors, but it's not immediately clear what I need to do to get this to bind my instance / make Functor a "method" rather than a simple function.

BobIsNotMyName
  • 415
  • 4
  • 11
  • Does this answer your question? [Decorators on bound methods with access to class and his ancestors](https://stackoverflow.com/questions/39698045/decorators-on-bound-methods-with-access-to-class-and-his-ancestors) Specifically, the first part of [this](https://stackoverflow.com/a/39698115/843953) answer, which defines a `wrapper` function and returns that from the decorator – Pranav Hosangadi May 17 '22 at 18:36
  • Thanks, but that looks different to me... That question is about a decorator getting info about an outer class, but using a "normal" decorator (i.e., decorator returns a function). This question is specifically about a decorator returning a function object (a class instance with __call__ method). Returning a normal function works fine as a method decorator. It's not clear what magic happens that transforms that normal function into an actual method that binds self, though. – BobIsNotMyName May 17 '22 at 18:45
  • Ok, so I think I already figured out a solution... It appears that using a `__get__` method with `return types.MethodType(self, obj)` works, but it's unclear to me if this is the "right" solution. So I'll leave this question open for now. – BobIsNotMyName May 17 '22 at 18:51
  • Functions are already first-class objects. What's the purpose of the `Functor` class? – chepner May 17 '22 at 19:33
  • @chepner - It's a custom caching library. Basically, I want to do the same thing as ring (https://ring-cache.readthedocs.io/en/stable/control.html). I want to be able to call `instance.some_method()` which will cache, and then something like `instance.some_method.execute()` to run the same operation uncached (which is going to get even more complicated from the descriptor perspective). But I also want this to apply to methods and have different caches based on instance, and I need to do some other things that I can't do with ring. – BobIsNotMyName May 17 '22 at 20:29

0 Answers0