13

I have

class A(object):
    def __init__ (self): raise NotImplementedError("A")

class B(A):
    def __init__ (self):
        ....

and pylint says

__init__ method from base class 'A' is not called

Obviously, I do not want to do

super(B, self).__init__()
  • so what do I do?

(I tried abc and got

Undefined variable 'abstractmethod'

from pylint, so that is not an option either).

sds
  • 58,617
  • 29
  • 161
  • 278
  • I din't see where do you used abstract class. If you are trying to inherit class A in B, and want to define __init__ in B, then please use super instead. Its a wrong implementation of abc class – James Sapam Aug 01 '14 at 03:56
  • Could've sworn that wasn't there when I read it. Did you remember to qualify `abstractmethod` with the module name and/or `from abc import abstractmethod`? – user2357112 Aug 01 '14 at 03:57
  • 1
    Reported at https://github.com/PyCQA/pylint/issues/3975 – Clément Dec 11 '20 at 19:34

3 Answers3

9

Ignore pylint. It's just a program that doesn't take abstract classes into account. Be confident you are smarter than it is. Pylint is a knee brace, not a crutch.

holdenweb
  • 33,305
  • 7
  • 57
  • 77
  • 2
    Thanks for the compliment, but I don't want to see any warnings or errors in production code. – sds Aug 01 '14 at 03:26
  • 1
    In which case you tend towards cargo cult programming. "No warnings" is too high a standard to avoid wasting effort. However, [this answer](http://stackoverflow.com/questions/1981978/what-makes-pylint-think-my-class-is-abstract) should give you some help. – holdenweb Aug 01 '14 at 03:31
  • @sds you can still disable the message locally for this specific case then – sthenault Aug 25 '14 at 07:10
  • You're not giving pylint enough credit, I think: it understands abstract classes quite well (it will warn you if you forget to implement an abstract method, for example) – Clément Dec 11 '20 at 19:35
  • Quite possibly true now, so thanks for the comment, but are you sure it was true in 2014? :D Happy to incorporate suggestions in an update ... – holdenweb Jun 14 '22 at 15:57
4

Using abc works for me:

import abc

class A(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def __init__(self):
        pass

class B(A):
    def __init__(self):
        super(B, self).__init__()

I get warnings, but nothing related to abc or the parent's __init__ not being called:

C:  1, 0: Missing module docstring (missing-docstring)
C:  3, 0: Invalid class name "A" (invalid-name)
C:  3, 0: Missing class docstring (missing-docstring)
R:  3, 0: Too few public methods (0/2) (too-few-public-methods)
C:  9, 0: Invalid class name "B" (invalid-name)
C:  9, 0: Missing class docstring (missing-docstring)
R:  9, 0: Too few public methods (0/2) (too-few-public-methods)
R:  3, 0: Abstract class is only referenced 1 times (abstract-class-little-used)

For what its worth, I'm with @holdenweb on this one. Sometimes you know better than pylint.

dano
  • 91,354
  • 19
  • 222
  • 219
  • aha, so the solution is to use `@abc.abstractmethod` instead of `@abstractmethod`. thanks. – sds Aug 01 '14 at 13:44
  • @sds Not really. The solution was to have `pass` instead of `raise NotImplementedError("A")` in A.__init__() – silentser Nov 15 '16 at 15:31
  • 3
    The best solution from pylint's perspective, but it's weird to call an abstract method... Abstract methods by design exist to be overridden, not called – kevlarr Jan 19 '18 at 17:43
  • This doesn't prevent A from being instantiated. – Clément Dec 12 '20 at 17:19
1

Defining an empty __init__ as an abstract method is not very useful.

Instead, make A inherit from ABC (ABstract Class), and use @abstractmethod decorator on methods that really need to be implemented by the user.

from abc import ABC, abstractmethod

class A(ABC):
    @abstractmethod
    def cool_method(self):
        raise NotImplemented

In that way, you would effectively not be able to instantiate A, and at the same time, you avoid the warning. Also consider that the default __init__ method for A when not implemented, would be something along the lines of:

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)

So additionally, it has the advantage that it respects the mro, if you later want to use A in a multiple inheritance setup, you will not run into problems.

Mateo de Mayo
  • 819
  • 9
  • 10
  • `Defining __init__ as an abstract method is not very useful.` = not true when you're defining an interface class and its method headers and you expect certain settings to be defined/done at object creation. Of course you could do `a = MyClass()` and then `a.my_init()` but why... – jave.web Jan 19 '21 at 14:29
  • @jave.web You are right, I've corrected it to be an *empty* `__init__` instead. – Mateo de Mayo Jan 19 '21 at 18:13