0

I have a class A which implements method x() and y() but I also have a class B which implements method z(). Assuming there is a base AbstractA class. how can I detect any calls on class A which aren't implemented e.g. z() and forward them to class B? Please note that I can't have A inherit from B due to framework plumbings i.e.,

from abc import ABC, abstractmethod   

class AbstractA(ABC):
   # some magic for catching unimplemented method calls e.g. z
   # and forward them to B's. Here I have access to instances of
   # B e.g. context.b.z()
   
   @abstractmethod
   def x():
     pass

   @abstractmethod
   def y():
     pass

class A(AbstractA):
  def __init__(self):
    super().__init__()

  def x():
    print('running x()')

  def y():
    print('running y()')

class B:
  def __init__(some plumbing args):
     super().__init__(some plumbing args) 

  def z():
     print('running z()')
 
a = A()
a.x()
a.y()
a.z()

To give a bit of context on this use-case, I have a multi-layered architecture with a data access layer (DAL) and then a service application layer (SAL). The DAL is a collection of DAOs that take care of wrapping all database access use-cases. The SAL builds on top of the DAL and mash ups DAL's data plus business application logic.

For example, a PersonDao implementation and a PersonService. PersonService will call PersonDao to build the business logic API but some times client code may request PersonService to find a person by id which is implemented in PersonDao directly. Therefore, instead of explicitly implementing a pass through service method for each DAO method, have this pass through or delegation automated on the abstract base level of PersonService so that if you do person_service.find_by_id(3) it will go straight to PersonDao#find_by_id(id)'s effectively making the service implementation a facade to the underlying DAOs.

SkyWalker
  • 13,729
  • 18
  • 91
  • 187
  • does this help? https://stackoverflow.com/questions/21961806/method-delegation-in-python – nadine May 19 '23 at 16:00
  • Do you know the classes/methods to delegate to ahead of time (i.e. statically)? – ChrisGS May 19 '23 at 16:03
  • @ChrisGS yes I do, their interfaces are defined in an abstract class `AbstractDao` and each Dao implementation e.g., `PersonDao` – SkyWalker May 19 '23 at 16:03
  • `B.z` should expect an instance of `B` as its first argument (or is `z` a static method?). In general, you can't "delegate" a call to `a.z` to a function that may have no idea what to do with an instance of `A`. – chepner May 19 '23 at 17:16

1 Answers1

1
from abc import ABC, abstractmethod
from inspect import isfunction

class AbstractA(ABC):
    # some magic for catching unimplemented method calls e.g. z
    # and forward them to B's. Here I have access to instances of
    # B e.g. context.b.z()

    @abstractmethod
    def x(self):
        pass
    @abstractmethod
    def y(self):
        pass

class A(AbstractA):
    def __init__(self):
        super().__init__()
        self.checker = 'value in A'

    def x(self):
        print('running x()')

    def y(self):
        print('running y()')

class B:
    def __init__(self, some_plumbing_args = None):
        self.checker = 'value in B'
    
    def z(self):
        print('running z()')
        print(self.checker)

Get functions' name only in class B. Bind the functions to class A.

functions_name_of_A = set(name for name, obj in A.__dict__.items() if isfunction(obj) == True and not name.startswith('__'))
functions_name_of_B = set(name for name, obj in B.__dict__.items() if isfunction(obj) == True and not name.startswith('__'))
functions_name = functions_name_of_B - functions_name_of_A

for name in functions_name:
    setattr(A, name, B.__dict__[name])

The value only in class A is showed by z().

a = A()
a.x()
a.y()
a.z()
>>> running x()
>>> running y()
>>> running z()
>>> value in A

The value only in class B is showed by z(), too.

b = B()
b.z()
>>> running z()
>>> value in B