Python Design Question – Concrete classes with different signature

Question:

I have two classes with similar methods; however, there are some different mandatory parameters in one class.

e.g.

class NamespaceScoped:
    def get_object(self, name, namespace):
        pass
    def delete_object(self, name, namespace):
        pass

class ClusterScoped:
    def get_object(self, name):
        pass
    def delete_object(self, name):
        pass

I need to create an interface for the above classes. Since the methods are more or less the same, with only the signature varying a bit – is it a good design to have an Abstract class with the same operations but allow the implementation class to have a different signature?

e.g.

class InterfaceClient(ABC):
    def get_object(self, name):
        pass
    def delete_object(self, name):
        pass

In Pycharm – I get the warning that the signature is different for class NamespaceScoped.

I could technically do **kwargs, but I don’t think I can enforce the mandatory parameters easily.

Is it an ok design to go with the above approach? An alternative to this is to have two abstract classes (one with namespace mandatory and the other with not); however, I see the declaration of the methods as are kind of duplicate.

Asked By: Vijay Nidhi

||

Answers:

If you want to have one common interface, then I totally agree with the @deceze’s comment above:

You can’t reasonably define a common interface if the signatures of the functions are different.

So you should make their signatures similar to each other.

From another point of view, both methods of the InterfaceClient are instance methods, the NamespaceScoped class can have a namespace member property (provided by the constructor or a setter method) by giving the ability to have one common interface for both NamespaceScoped and ClusterScoped classes.

from abc import ABC, abstractmethod


class InterfaceClient(ABC):
    @abstractmethod
    def get_object(self, name):
        pass

    @abstractmethod
    def delete_object(self, name):
        pass


class NamespaceScoped(InterfaceClient):
    def __init__(self, namespace):
        self.namespace = namespace

    def get_object(self, name):
        pass

    def delete_object(self, name):
        pass


class ClusterScoped(InterfaceClient):
    def get_object(self, name):
        pass

    def delete_object(self, name):
        pass
Answered By: Artyom Vancyan
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.