2

Let's say there is a class SomeClass with function func which returns int. How can we implement a similar interface?

class SomeClass:
    @overload
    @property
    def f(self) -> int:
        return 1

    @overload
    def f(self, x: int) -> int:
        return x


if __name__ == "__main__":
    obj = SomeClass()
    print(obj.f)  # print 1
    print(obj.f(5))  # print 5

Preferably a solution without external modules, but if this is problematic, it is acceptable.

P.S. overload decorator doesn't exist, this is just an example.

Edit:

Function overloading is given only as an example implementation, but it is not necessary. The main goal is to implement this interface type:

obj = SomeClass()
obj.f  # returns 1 (without brackets, works like property)
obj.f(5)  # returns 5 (with brackets, works like a normal function)
7
  • Python does not support method overloading Commented Dec 7, 2021 at 0:30
  • There is such a thing as @overload in Python, but you can't use it to have obj.f be both an int and a callable. Commented Dec 7, 2021 at 0:35
  • @Samwise right, it is merely for type hinting, it doesn't actually allow for ad hoc polymorphism Commented Dec 7, 2021 at 0:38
  • You can also combine it with *args, **kwargs to have a method that behaves differently (and has different type signatures) depending on the type of its arguments. But that still doesn't help OP with what they're trying to do. That requires significantly more shenanigans. Commented Dec 7, 2021 at 0:39
  • dang, it got closed right before I could post the answer to how you actually do this (it involves magic methods on the object returned by the property) :P Commented Dec 7, 2021 at 0:41

1 Answer 1

2

The core of your problem here is that you want obj.f to be simultaneously an int and a function:

    print(obj.f)     # print 1
    print(obj.f(5))  # print 5

This is technically possible by creating a callable int with the desired behavior, and having your property return that:

class SomeClass:
    class TrickyInt(int):
        def __new__(cls, val):
            return super().__new__(cls, val)

        def __call__(self, val):
            return self.__class__(val)

    @property
    def f(self):
        return self.TrickyInt(1)


if __name__ == "__main__":
    obj = SomeClass()
    print(obj.f)     # prints 1
    print(obj.f(5))  # prints 5

This is a lot of trouble to go to in order to implement a very unintuitive interface, though. I would recommend having this be a regular old method:

class SomeClass:
    def f(self, val=1):
        return val


if __name__ == "__main__":
    obj = SomeClass()
    print(obj.f())   # prints 1
    print(obj.f(5))  # prints 5
Sign up to request clarification or add additional context in comments.

2 Comments

This should almost certainly never be used
beware the magic!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.