In a new project, instead of defining methods inside the bodies of my classes, I would like to use multimethods
exclusively and define nothing inside my classes except for data members.
In other words, instead of this:
class A():
x: int = 0
def f(self):
print(f"A.f(self): x = {self.x}")
I would like to write this:
class B():
x: int = 0
@multimethod
def g(b: B):
print(f"g(b: B): x = {b.x}")
Now, I can call f
using method syntax:
a = A()
a.f()
And g
using function syntax:
b = B()
g(b)
However, not the other way around:
a = A()
f(a) # NameError: name 'f' is not defined
b = B()
b.g() # AttributeError: 'B' object has no attribute 'g'
This means I have to give up a lot of convenience. In particular, implementing something like __str__
as a multimethod
does not give me the kind of behavior I would get if it was implemented inside a class.
class B():
x: int = 0
@multimethod
def __str__(b: B) -> str:
return f"B({b.x})"
Calling print(B())
outputs something along the lines of <__main__.B object at 0x7fb229c6a5b0>
instead of B(0)
.
Going another step further, it would even be imaginable for an arbitrarily named function having the correct signature (like somefn
below) to fill in for __str__
.
class B():
x: int = 0
@multimethod
def somefn(b: B) -> str:
return f"B({b.x})"
Is there a way to keep the bodies of my classes empty and make the appropriate multimethods
act as though they were defined inside the respective body?
Admittedly, what I am trying to do here is kind of like opting out of the built in object oriented features of Python and, at least partially, replacing them with something more general. This seems like bending the language quite a bit. So, even if multimethods
does not fully support this interoperability in the moment, is it likely that interfacing between traditional classes and multiple dispatch will become more ergonomic in the future?