Inheritance: changing the signature of child methods

I am trying to figure out what is the best practice in Python inheritance principles when there is a "bad idea" to change the method signature of a child.

Suppose we have a base class BaseClient

with a method already implemented create

(and some abstract ones) that is suitable for almost all "descendants" except one:

 class BaseClient(object):

     def __init__(self, connection=None):
         pass

     def create(self, entity_id, data=None):
         pass

 class ClientA(BaseClient):
     pass

 class ClientB(BaseClient):
     pass

      

A single class ClientC

needs a different method implementation create

with a slightly different method signature

 class ClientC(BaseClient):
     ....
     def create(self, data):
         pass

      

So the question is, how do you do it in a more "pythonic" way, taking into account best python practice? Of course we can use *args, **kwargs

other approaches **kwargs

in the parent (child) method as well, but I'm afraid my code is becoming less readable (self-documenting).

+3


source to share


2 answers


I'm not sure if there is a way like Pythonic, since you can do the same as in the question. Rather, I would say that this is more about OOP than about Python.

So I am assuming there are other methods implemented in BaseClient

besides create

that other children share (otherwise no point makes a ClientC

child BaseClient

). In your case, it looks like it ClientC

deviates from the rest by requiring a different method signature create

. Then it might be worth considering separating them?

For example, you can have root BaseClient

implement all the common methods except create

, and then add two more "base" children, for example:

class EntityBasedClient(BaseClient):
    def create(self, entity_id, data=None):
        pass

class DataBasedClient(BaseClient):
    def create(self, data):
        pass

      



So now you can inherit without breaking any rule:

class ClientA(EntityBasedClient):
     pass

class ClientB(EntityBasedClient):
     pass

class ClientC(DataBasedClient):
    pass

      


Also, if the implementation of the two versions is create

fairly similar, you can avoid code duplication by adding a more general private method implemented in BaseClient

signed _create(self, entity_id=None, data=None)

, then call it with the appropriate arguments from within EntityBasedClient

and DataBasedClient

.

0


source


I would say just add the parameter back as a keyword with a default of None. Then raise a bug that explains that some input data was lost.

 class ClientC(BaseClient):
 ....
     def create(self,entity_id=None, data):
         if entity_id:
             raise RedudantInformationError("Value for entity_id does nothing")
         pass

      



This way, whenever a programmer tries to process child C like other children, he will get a warning that reminds him, but nevertheless, he can easily follow step by step using try syntax.

0


source







All Articles