60

I'm working on a kind of lib, and I'm getting an error.

  • Here is my code. Of course @abc.abstractmethod have to be uncommented
  • Here are my tests

Sorry couldn't just copy and paste it

I went on the basis that the code below works.

test.py:

import abc
import six

@six.add_metaclass(abc.ABCMeta)
class Base(object):

    @abc.abstractmethod
    def whatever(self,):
        raise NotImplementedError

class SubClass(Base):

    def __init__(self,):
    
        super(Base, self).__init__()
        self.whatever()

    def whatever(self,):
        print("whatever")

In the python shell:

>>> from test import *
>>> s = SubClass()
whatever

For my roster module, why am I getting this error:

Can't instantiate abstract class Player with abstract methods _Base__json_builder, _Base__xml_builder
starball
  • 20,030
  • 7
  • 43
  • 238
josuebrunel
  • 1,071
  • 1
  • 10
  • 19

4 Answers4

81

Your issue comes because you have defined the abstract methods in your base abstract class with __ (double underscore) prepended. This causes python to do name mangling at the time of definition of the classes.

The names of the function change from __json_builder to _Base__json_builder or __xml_builder to _Base__xml_builder . And this is the name you have to implement/overwrite in your subclass.

To show this behavior in your example -

>>> import abc
>>> import six
>>> @six.add_metaclass(abc.ABCMeta)
... class Base(object):
...     @abc.abstractmethod
...     def __whatever(self):
...             raise NotImplementedError
...
>>> class SubClass(Base):
...     def __init__(self):
...             super(Base, self).__init__()
...             self.__whatever()
...     def __whatever(self):
...             print("whatever")
...
>>> a = SubClass()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class SubClass with abstract methods _Base__whatever

When I change the implementation to the following, it works

>>> class SubClass(Base):
...     def __init__(self):
...             super(Base, self).__init__()
...             self._Base__whatever()
...     def _Base__whatever(self):
...             print("whatever")
...
>>> a = SubClass()
whatever

But this is very tedious , you may want to think about if you really want to define your functions with __ (double underscore) . You can read more about name mangling here .

Anand S Kumar
  • 88,551
  • 18
  • 188
  • 176
  • Thanks @AnandSKumar, it's weird because i tried it lol. Have good one buddy – josuebrunel Jul 16 '15 at 17:39
  • 9
    Am I the only one, who stumbled upon the Error Message? Maybe it's just me, but I'd expect something along these lines: _Can't instantiate subclass of abstract class Base __without__ methods some-method_. This confused me at first. – quapka Oct 21 '16 at 10:16
  • 2
    @quapka I think the error message seems fine. The error message indicates that the SubClass class has an 'abstract method' , and its not a concrete method, hence we cannot instantiate an object of it. – Anand S Kumar Nov 03 '16 at 17:48
  • 17
    @quapka I agree. The error message `Can't instantiate abstract class Foo with abstract methods abstract_method` is clearly wrong. The problem is not that an abstract class is being instantiated with a forbidden method, but that a subclass of an abstract class is being instantiated _without_ a required method. It should say something like `Can't instantiate subclass Foo of abstract class Bar without method abstract_method_that_must_be_overridden`. – Arthur Mar 30 '17 at 18:36
  • @Arthur You are an abstract class when you have abstract methods, so the error message is not wrong. If the abstract methods were overriden, you would not have abstract methods, and consequently you would not be an abstract class. – Géry Ogam Aug 03 '20 at 17:34
  • 1
    @Arthur Thanks for the clarification. The error message is indeed really confusing. – Houman May 16 '21 at 08:19
2

I got the same error below:

TypeError: Can't instantiate abstract class Animal with abstract methods sound

When I tried to instantiate Animal abstract class as shown below:

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def sound(self):
        print("Wow!!")

obj = Animal() # Here
obj.sound()

And also, I got the same error below:

TypeError: Can't instantiate abstract class Cat with abstract methods sound

When I didn't override sound() abstract method in Cat class, then I instantiated Cat class as shown below:

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def sound(self):
        print("Wow!!")

class Cat(Animal):
    pass # I didn't override "sound()" abstract method

obj = Cat() # Here
obj.sound()

So, I overrided sound() abstract method in Cat class, then I instantiated Cat class as shown below:

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def sound(self):
        print("Wow!!")

# I overrided "sound()" abstract method
class Cat(Animal):
    def sound(self):
        print("Meow!!")

obj = Cat() # Here
obj.sound()

Then, I could solve the error:

Meow!!
Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
1

The error text is a bit inaccurate. To be precise, you did not override the method of the parent class, because private methods and attributes cannot be inherited, which means they cannot be overridden.

But you can override protected methods (protected method should start with single underscore '_').

  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 23 '23 at 12:59
0

Easiest way to make it behave like it did in Python 2 is to use

exec('print("your code")', globals())

This will allow your code to access imports, classes and functions defined in the code will work correctly, etc.

This should only be done w/ code you trust.

blented
  • 2,699
  • 2
  • 23
  • 17