0

In Python, I would like to wrap both decorated functions or methods into a container class holding additional information and generally mark functions as "externally callable".

Given this little program rudely explains my attempt. This works with functions, but not with methods that belong to a class, as the self argument is expected.

from typing import Callable


class Exposed:
    def __init__(self, func: Callable):
        self.func = func

    def __call__(self, *args, **kwargs):
        return self.func(*args, **kwargs)


def exposed(func: Callable) -> Exposed:
    return Exposed(func)


@exposed
def add(x, y):
    return x + y


class MyClass:
    def __init__(self, value):
        self.value = value

    @exposed
    def mul(self, factor):
        return self.value * factor


result = add(3, 5)
print(result)  # 8

obj = MyClass(5)
result = obj.mul(3)
print(result)  # 15

when running this, the following error occurs:

$ python x.py
8
Traceback (most recent call last):
  File "~/x.py", line 34, in <module>
    result = obj.mul(3)
             ^^^^^^^^^^
  File "~/x.py", line 9, in __call__
    return self.func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: MyClass.mul() missing 1 required positional argument: 'factor'

I know that the problem is with the method, expecting the self-parameter or, more specific, a binding. When the decorator is executed, there is no binding. Maybe my entire approach is wrong, but I'm out of ideas, and several solutions I've tried didn't work. I'm on current stable Python 3.11. Can somebody help?

glasflügel
  • 325
  • 2
  • 11
  • The short version: the way methods work in Python is that the class contains a perfectly ordinary function; when you look up the method from an instance, the *lookup process* finds the function and *then automatically checks* what it finds, to see if it is a *descriptor*. Functions are; they implement `__get__` to create a bound-method object instead of returning themselves. But your decorator replaces the function with an instance of another class, which does not have that logic. – Karl Knechtel Jul 26 '23 at 23:35

0 Answers0