I have a couple classes and a function:
from functools import partial
def fn(other, self, name):
print(f"calling {name} with {other}")
func = getattr(self.a, name)
return func(other)
class A:
def __add__(self, other):
return 9
def __mul__(self, other):
return 7
def __sub__(self, other):
return 8
class B:
def __init__(self,a):
self.a = a
for name in ['add', 'sub']:
name = f"__{name}__"
p = partial(fn, self=self,name=name)
setattr(self, name, p)
p.__name__ = name
I want to be able to use the forward the magic methods to an existing property. I don't want to inherit the class because I don't want all the builtins. just a couple. For instance I might want to use multiply from a different class. I'm trying to avoid coding like this:
def __add__(self, other):
self.a.__add__(other)
using the above code I receive the following:
>>> b = B(A())
>>> b + 3
TypeError Traceback (most recent call last)
<ipython-input-40-fa904b7bb783> in <module>
----> 1 b + 3
2
TypeError: unsupported operand type(s) for +: 'B' and 'int'
>>> b.__add__(3)
calling __add__ with 3
9
Maybe I'm missing something simple but I can't find a way to dynamically add the builtin function.
The main problem to get around is that magic methods like __add__
are looked up on the class, not on the object itself; otherwise you could just write self.__add__ = a.__add__
in the __init__
method. To get around this, we need to declare methods on the class B
, not on individual instances of it.
The function delegate
defined below works by adding a method to the B
class. This method takes self
which will be a B
instance, so it has to dynamically load the a
attribute and then its __add__
method.
class A:
def __add__(self, other):
return 9
def __mul__(self, other):
return 7
def __sub__(self, other):
return 8
class B:
def __init__(self, a):
self.a = a
def delegate(cls, attr_name, method_name):
def delegated(self, *vargs, **kwargs):
a = getattr(self, attr_name)
m = getattr(a, method_name)
return m(*vargs, **kwargs)
setattr(cls, method_name, delegated)
delegate(B, 'a', '__add__')
delegate(B, 'a', '__sub__')
Example:
>>> b = B(A())
>>> b + 3
9
>>> b - 4
8