Method override signature match warning - Liskov Substitution Principle?

72 Views Asked by At

I have the following code in PyCharm:

from abc import ABC, abstractmethod


class Parent(ABC):
    @abstractmethod
    def foo(self, a):
        raise NotImplementedError
        

class Child(Parent):
    @staticmethod
    def foo(a):
        print(a)


class OtherChild(Parent):
    @staticmethod
    def foo(a, b=2):
        print(a, b)


class ThirdChild(Parent):
    def foo(self, a):
        print(self, a)

Pycharm gives me a warning for "Signature of method 'Child.foo()' does not match signature of the base method in class 'Parent'". But see no such warnings on OtherChild.foo() or ThirdChild.foo().

I'm tyring to understand if I am see false positive or false negative warnings for signature matching.

I think that all three children are complian with the Liskov substitution principle because Parent.foo() has one required argument and each child method also has one required argument. I don't know if instance vs static method has any implications for Liskov substituion.

Basically I see two strange things here.

  • If you compare Child.foo() and OtherChild.foo() you can see they are both static methods (whereas Parent.foo() is an instance method). Child.foo() gets the warning but OtherChild.foo() does not. Somehow adding the extra optional argument clears the signature matching warning. (adding a second required argument brings back the signature warning as I would expect based on LSP).
  • Now, if you compare Child.foo() with ThirdChild.foo() we see they are both methods with one required argument, a but Child.foo() is static whereas ThirdChild.foo() is an instance method. ThirdChild.foo() does not get the warning.

So my questions are:

  • Are all three of these classes indeed compliant with Liskov Substitution Principle? If not, why?
  • Why do I only see the warning on Child.foo()? Is this expected behavior or is this actually a PyCharm bug that I should report in their bug tracking system?

One workaround is I can do

class Child(Parent):
    def foo(self, a):
        print(a)

This is the same as the code above but I've left off the @staticmethod decorator around foo(). Normally this would give a Method 'foo' may be static warning, but in this case, I guess because the method is overriding a parent method, the warning is not present. This code gives no warnings.

0

There are 0 best solutions below