39

I was wondering if its possible when creating an abstract class with abstract methods if its possible to allow the implementations of those methods in the derived classes to have different amounts of parameters for each function.

I currently have for my abstract class

from abc import ABCMeta, abstractmethod

class View(metaclass=ABCMeta):
    @abstractmethod
    def set(self):
        pass

    @abstractmethod
    def get(self):
        pass

But I want to be able to implement it in one class with set having 1 parameter and get having 2 (set(param1) and get(param1, param2)), and then in another class also inherit it but have 0 parameters for set and 2 for get (set() and get(param1, param2)).

Is this possible and if so how would I go about doing it

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
1seanr
  • 657
  • 2
  • 7
  • 18
  • 4
    While you *can* do that, that's a really weird thing to do. The semantics of an abstract method almost always include the parameters it should take. You may want to reconsider whether this abstract method or abstract class actually make sense. – user2357112 Mar 14 '17 at 06:28

2 Answers2

60

No checks are done on how many arguments concrete implementations take. So there is nothing stopping your from doing this already.

Just define those methods to take whatever parameters you need to accept:

class View(metaclass=ABCMeta):
    @abstractmethod
    def set(self):
        pass

    @abstractmethod
    def get(self):
        pass


class ConcreteView1(View):
    def set(self, param1):
        # implemenation

    def get(self, param1, param2):
        # implemenation


class ConcreteView2(View):
    def set(self):
        # implemenation

    def get(self, param1, param2):
        # implemenation
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • 17
    ohk it must just be pep8 in pycharm telling me off then thank you – 1seanr Mar 14 '17 at 06:26
  • 6
    Isn't there any way that does not lead to a warning? – matheburg Jul 20 '19 at 11:07
  • 1
    @matheburg *what* warning? Python itself doesn’t issue warnings for this. Are you perhaps using a linter (perhaps as an IDE feature)? – Martijn Pieters Jul 20 '19 at 14:19
  • 6
    @MartijnPieters `Signature of method '...' does not match signature of base method in class '...'` is shown by PyCharm at least. Looks like this is some PyCharm internal warning, not PEP8, see e.g. [this example](https://stackoverflow.com/questions/45555136/django-signature-of-method-does-not-match-signature-of-base-method-in-class). So let's reformulate my question: if one is warned about this, what would be a best practice design pattern for that case? – matheburg Jul 21 '19 at 08:11
  • 2
    @matheburg: don't change your method signatures, at least not the required components. Use optional arguments to extend (so keyword arguments). – Martijn Pieters Jul 21 '19 at 11:31
  • 1
    @MartijnPieters your proposed solution contradicts with your last comment "_don't change your method signatures, at least not the required components_" since you introduce new positional arguments in both, `ConcreteView1` and `ConcreteView2`. How would you solve this contradiction? What's your daily "best-practice" for this? – daniel451 Mar 05 '21 at 10:41
  • 1
    @daniel451: The answer addresses the technicalities of the Python `abc` module and the specific call signatures the OP used in their question. I try to stick to the Liskov substitution principle in my own work, so I'd not use positional parameters in this case. – Martijn Pieters Mar 05 '21 at 12:39
5

python 3.8

from abc import ABC, abstractmethod


class SomeAbstractClass(ABC):
    @abstractmethod
    def get(self, *args, **kwargs):
        """
        Returns smth
        """

    @abstractmethod
    def set(self, key, value):
        """
        Sets smth
        """

class Implementation(SomeAbstractClass):
    def set(self, key, value):
        pass

    def get(self, some_var, another_one):
        pass

Works perfectly, no warnings, no problems

Bram Vanroy
  • 27,032
  • 24
  • 137
  • 239
n0nSmoker
  • 832
  • 11
  • 26
  • 2
    and what if the `Implementation` class has some children class and that class calls `get` method ? the error I am getting is something is like this `W0221: Number of parameters was 2 in 'BaseSetter.create' and is now 4 in overridden 'DocumentsTotalsSetter.create' method (arguments-differ)` – rickster May 20 '22 at 18:38
  • I would say that you should not do this at least it does not look pythonic from my perspective. If a method has different signature in every descendant you should extract common functionality and reorganise logic. But its just my personal opinion. If you show the code I can say more – n0nSmoker Jun 14 '22 at 12:17