Consider the following class hierarchy:
       A
       |
 _____________
 |     |     |
Foo   Bar   Baz
The class A defines a __call__ method, which Foo, Bar and Baz implement. The classes also define various other methods I'm interested in. All three classes come from a third party library, so I do not want to change their implementation. However, in some cases at runtime, I would like to alter the implementation of Foo's, Bar's and Baz' __call__ method. Right now, I did this by defining my own classes, which solely override the __call__ method:
Foo   Bar   Baz
 |     |     |
Foo1  Bar1  Baz1
Then, depending on the situation, I instantiate the desired class to a common variable. I'm not satisfied with this solution, as it has the following drawbacks:
The additions I make to
__call__are not necessarily uniquely determined by the class.Bar1andBaz1might share the implementation of__call__(butBarandBazdiffer in other aspects). So, as far as I understand, I need to repeat code.At runtime, instantiating the desired class requires m × n case distinctions (where m is the number of classes at the level of
Foo,Bar, andBazand n is the number of classes at the level ofFoo1,Bar1, andBaz1). This will grow rapidly as m or n increase. Ideally, I would like the number of case distinction to be m + n.
I already had a look at https://python-patterns.guide/gang-of-four/composition-over-inheritance/#solution-3-the-decorator-pattern, at Cannot overwrite implementation for __call__ and at __call__ method of type class. However, these solutions do not fit perfectly to my case, as (1) I'm overriding a dunder method (2) of third party classes and (3) still would like to have access to the other class methods of Foo, Bar, and Baz.
Is there an elegant why to achieve what I am looking for?
Edit: The change of __call__ at runtime should only affect the instance object, not the class or all objects of that class at once.
Edit 2 (requested by @enzo):
# -*- coding: utf-8 -*-
from abc import ABCMeta, abstractmethod
class A(metaclass=ABCMeta):
    @abstractmethod
    def __call__(self, x, y):
        """Docstring A"""
    
    @abstractmethod
    def method1(self, a, b):
        """Docstring method1"""
class Foo(A):
    def __call__(self, x, y):
        return x + y # indeed, no dependence on `self`
    
    def method1(self, a, b):
        # but this might depend on `self`
        pass
class Bar(A):
    def __call__(self, x, y):
        return x * y # indeed, no dependence on `self`
    
    def method1(self, a, b):
        # but this might depend on `self`
        pass
    def method2(self, c, d):
        # but this might depend on `self`
        pass
class Baz(A):
    def __call__(self, x, y):
        return x ** y # indeed, no dependence on `self`
    
    def method1(self, a, b):
        # but this might depend on `self`
        pass
    def method2(self, c, d):
        # but this might depend on `self`
        pass