From the docs:

A class that has a metaclass derived from ABCMeta cannot be instantiated unless all of its abstract methods and properties are overridden.

Conversely, this means that any class with no abstract methods or properties like your AbstractClass can be instantiated.


If you want to disallow instantiation of the topmost parent class, you can write a custom class that performs a type check in its __new__ method:

class SubclassOnlyABC(object):
    __metaclass__ = abc.ABCMeta

    def __new__(cls, *args, **kwargs):
        if cls.__bases__ == (SubclassOnlyABC,):
            msg = 'Abstract class {} cannot be instantiated'.format(cls.__name__)
            raise TypeError(msg)

        return super(SubclassOnlyABC, cls).__new__(cls, *args, **kwargs)
class AbstractClass(SubclassOnlyABC):
    pass

class ChildClass(AbstractClass):
    pass

ChildClass()  # works because it's a child class of an abstract class
AbstractClass()  # throws TypeError because its parent class is "object"

You can also write a __new__ method that prevents instantiation of classes with no abstract methods:

class NonEmptyABC(object):
    __metaclass__ = abc.ABCMeta

    def __new__(cls, *args, **kwargs):
        # check if ANY abstractmethod exists
        for parentcls in cls.__mro__:
            if any(getattr(attr, '__isabstractmethod__', False)
                               for attr in vars(parentcls).values()):
                break
        else:
            msg = 'Abstract class {} cannot be instantiated'.format(cls.__name__)
            raise TypeError(msg)

        return super(NonEmptyABC, cls).__new__(cls, *args, **kwargs)
class EmptyAbstractClass(NonEmptyABC):
    pass

class NonemptyAbstractClass(NonEmptyABC):
    @abc.abstractmethod
    def foo(self):
        pass

class NonemptyChild(NonemptyAbstractClass):
    def foo(self):
        pass

NonemptyChild()  # works because "foo" is an abstractmethod
EmptyAbstractClass()  # throws TypeError because there are no abstractmethods
Answer from Aran-Fey on Stack Overflow
🌐
Reddit
reddit.com › r/learnpython › what's the point of abc & @abstractmethod
r/learnpython on Reddit: What's the point of ABC & @abstractmethod
July 27, 2021 -

Hello. In this first example, I have a short and straightforward code w/ a class for interface. It doesn't inherit from ABC and doesn't have any abstract methods.

class Abs():
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def go_to(self):
        return f"{self.name} is going to {self.place}."
        
class Teacher(Abs):
    place = "work"

class Student(Abs):
    place = "school"
    
t1 = Teacher("James", 56)
s1 = Student("Tim", 15)

print(t1.go_to())
print(s1.go_to())

In this second example, it's the exact opposite.

from abc import ABC, abstractmethod

class Abs(ABC):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    @abstractmethod
    def go_to(self):
        ...
        
class Teacher(Abs):
    place = "work"
    
    def go_to(self):
        return f"{self.name} is going to {self.place}."

class Student(Abs):
    place = "school"
    
    def go_to(self):
        return f"{self.name} is going to {self.place}."
    
t1 = Teacher("James", 56)
s1 = Student("Tim", 15)

print(t1.go_to())
print(s1.go_to())

Both examples have the same output. In the tutorials/articles I've read, most times the second example is preferred. In the abstract class, abstract methods get defined and decorated, and then in the inheriting classes they all get redefined with the rest of the logic. What's the point of creating a class w/ abstract methods which later on we redefine? What issue does that solve? Why not just proceed as in the first example - simple, less code, one parent class for the interface, if we need to add other details, we do so in the base class once and handle the extra logic with that additional info there. Doesn't the first code present a better example of loose coupling - just one connection between parent and child classes, where in the second code, we get connections between parent/child in every method that we redefine? I feel like I'm missing something, because to me, the second example is much more spaghetti-like. If anyone can explain why it's a good practice to redefine abstract methods that would be nice. Also, is it a bad practice to write code as in the first example, w/o ABC+@abstractmethod in the parent class?
Thanks.

Top answer
1 of 5
10
So your examples are a bit problematic because you would never use @abstractmethod in that situation. In your example there is no reason not to define the function only in the parent class--the parent knows everything it needs in order to execute the function, and the children don't change the execution at all. Also, Abs is a terrible name for a class. @abstractmethod is for when you: Require all children to have a method Don't have enough information to define that method in the parent Essentially, it "requires" child classes to define this method. This allows you to include the method in your parent interface so you can document it but raises a sensible error if the child doesn't re-define it. This is mostly useful for parent classes that will never have direct instances--only instances of subclasses. Consider designing a shooter game like Doom or Quake. You might represent various objects and enemies as class instances. To keep the game synced, every clock tick all the objects need to "update" themselves. Enemies might move around, lights might blink, and items might recharge. They all need to do something, but what they do is completely unique to each class. In a case like this, you might define the update() method in the parent Object class. This is mostly a convenience feature--you can write the same code perfectly well without it. However, it allows you to refer to all objects collectively (isinstance(o, Object)) through the parent class, and still ensure that update() exists, even though the parent doesn't know what to do with it. You could easily define update() in the parent and have it do nothing, but this prevents errors from being raised if you call this on a child class that hasn't re-defined the method.
2 of 5
3
let's imagine a List interface - we'll have the operations of append and pop class List(ABC): @abstractmethod def append(self, val): pass @abstractmethod def pop(self): pass now we could create class LinkedList(List) and class ArrayList(List) where we'd implement the methods for both of the list types the reason for using ABC and @abstractmethod is because it doesn't make sense to be able to be able to instantiate a List - that doesn't have an implementation. it only describes what behaviour an implementation should have to provide. think of it as providing a contract by which all users of an object know what behaviour to expect abstract classes and methods are more useful in languages such as java where you can't rely on duck typing void doThing(List list) this would take any subclass of List and be checked at compile time to have the expected methods of append and pop
Top answer
1 of 5
11

From the docs:

A class that has a metaclass derived from ABCMeta cannot be instantiated unless all of its abstract methods and properties are overridden.

Conversely, this means that any class with no abstract methods or properties like your AbstractClass can be instantiated.


If you want to disallow instantiation of the topmost parent class, you can write a custom class that performs a type check in its __new__ method:

class SubclassOnlyABC(object):
    __metaclass__ = abc.ABCMeta

    def __new__(cls, *args, **kwargs):
        if cls.__bases__ == (SubclassOnlyABC,):
            msg = 'Abstract class {} cannot be instantiated'.format(cls.__name__)
            raise TypeError(msg)

        return super(SubclassOnlyABC, cls).__new__(cls, *args, **kwargs)
class AbstractClass(SubclassOnlyABC):
    pass

class ChildClass(AbstractClass):
    pass

ChildClass()  # works because it's a child class of an abstract class
AbstractClass()  # throws TypeError because its parent class is "object"

You can also write a __new__ method that prevents instantiation of classes with no abstract methods:

class NonEmptyABC(object):
    __metaclass__ = abc.ABCMeta

    def __new__(cls, *args, **kwargs):
        # check if ANY abstractmethod exists
        for parentcls in cls.__mro__:
            if any(getattr(attr, '__isabstractmethod__', False)
                               for attr in vars(parentcls).values()):
                break
        else:
            msg = 'Abstract class {} cannot be instantiated'.format(cls.__name__)
            raise TypeError(msg)

        return super(NonEmptyABC, cls).__new__(cls, *args, **kwargs)
class EmptyAbstractClass(NonEmptyABC):
    pass

class NonemptyAbstractClass(NonEmptyABC):
    @abc.abstractmethod
    def foo(self):
        pass

class NonemptyChild(NonemptyAbstractClass):
    def foo(self):
        pass

NonemptyChild()  # works because "foo" is an abstractmethod
EmptyAbstractClass()  # throws TypeError because there are no abstractmethods
2 of 5
10

I usually just declare the base class's __init__ with @abc.abstractmethod. If my base class does not have an __init__, I add a trivial one.

Something like this:

class AbstractClass(abc.ABC):
    @abc.abstractmethod
    def __init__(self):
        pass

    # other useful non-abstract methods...


class ChildClass(AbstractClass):
    def __init__(self):
        pass


if __name__ == '__main__':
    child = ChildClass()  # allowed
    abstract = AbstractClass()  # TypeError
Discussions

AbstractMethods and NotImplementedError
Are there any experts on the use of ABCs and abstractmethod who could weigh in on a documentation issue please? The documentation for the exception says that abstract methods should raise NotImplementedError. Obviously this is not mandatory. Abstract methods can have default implementations. More on discuss.python.org
🌐 discuss.python.org
0
1
December 22, 2022
You don't need to raise NotImplementedError for abstract methods
Documentation In the documentation for NotImplementedError, we see the following: cpython/Doc/library/exceptions.rst Lines 299 to 304 in a7715cc .. exception:: NotImplementedError This exception is derived from :exc:`RuntimeError`. In us... More on github.com
🌐 github.com
4
December 21, 2022
class - Is it possible to make abstract classes in Python? - Stack Overflow
Then, I can't instantiate G either, since it calls its super class's __new__ method. Is there a better way to define an abstract class? ... Yes, you can create abstract classes in python with the abc (abstract base classes) module. More on stackoverflow.com
🌐 stackoverflow.com
Calling abstract methods - Typing - Discussions on Python.org
PEP 544 indicates that a type checker should generate an error if a class that explicitly derives from the protocol attempts to call a method through super() if that method is unimplemented in the protocol. class Proto(… More on discuss.python.org
🌐 discuss.python.org
1
January 6, 2024
🌐
GitHub
github.com › microsoft › pyright › issues › 2547
No errors when using `@abstractmethod` on non-ABC class or when instantiating such class · Issue #2547 · microsoft/pyright
November 6, 2021 - To Reproduce # pyright: strict from abc import abstractmethod class MyAbstract: # does not inherit from ABC @abstractmethod # no error def do_something(self): pass c = MyAbstract().do_something() # also no error Expected behavior An erro...
Author   Tomaz-Vieira
🌐
Python
docs.python.org › 3 › library › abc.html
abc — Abstract Base Classes
Dynamically adding abstract methods to a class, or attempting to modify the abstraction status of a method or class once it is created, are only supported using the update_abstractmethods() function. The abstractmethod() only affects subclasses derived using regular inheritance; “virtual subclasses” registered with the ABC’s register() method are not affected.
🌐
Astral
docs.astral.sh › ruff › rules › abstract-base-class-without-abstract-method
abstract-base-class-without-abstract-method (B024) | Ruff
If an abstract base class has no abstract methods or properties, you may have forgotten to add an abstract method or property to the class, or omitted an @abstractmethod decorator. If the class is not meant to be used as an interface, consider removing the ABC base class from the class definition.
🌐
Python.org
discuss.python.org › python help
AbstractMethods and NotImplementedError - Python Help - Discussions on Python.org
December 22, 2022 - Are there any experts on the use of ABCs and abstractmethod who could weigh in on a documentation issue please? The documentation for the exception says that abstract methods should raise NotImplementedError. Obviously this is not mandatory. Abstract methods can have default implementations.
🌐
GitHub
github.com › python › cpython › issues › 100400
You don't need to raise NotImplementedError for abstract methods · Issue #100400 · python/cpython
December 21, 2022 - If "abstract base classes" are meant to mean ABCs from the standard library, this is unnecessary as the ABC metaclass will prohibit instantiation of any derived class that doesn't implement an abstract method.
Author   Xophmeister
Find elsewhere
Top answer
1 of 13
760

Use the abc module to create abstract classes. Use the abstractmethod decorator to declare a method abstract, and declare a class abstract using one of three ways, depending upon your Python version.

In Python 3.4 and above, you can inherit from ABC. In earlier versions of Python, you need to specify your class's metaclass as ABCMeta. Specifying the metaclass has different syntax in Python 3 and Python 2. The three possibilities are shown below:

Copy# Python 3.4+
from abc import ABC, abstractmethod
class Abstract(ABC):
    @abstractmethod
    def foo(self):
        pass
Copy# Python 3.0+
from abc import ABCMeta, abstractmethod
class Abstract(metaclass=ABCMeta):
    @abstractmethod
    def foo(self):
        pass
Copy# Python 2
from abc import ABCMeta, abstractmethod
class Abstract:
    __metaclass__ = ABCMeta

    @abstractmethod
    def foo(self):
        pass

Whichever way you use, you won't be able to instantiate an abstract class that has abstract methods, but will be able to instantiate a subclass that provides concrete definitions of those methods:

>>> Abstract()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Abstract with abstract methods foo
>>> class StillAbstract(Abstract):
...     pass
... 
>>> StillAbstract()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class StillAbstract with abstract methods foo
>>> class Concrete(Abstract):
...     def foo(self):
...         print('Hello, World')
... 
>>> Concrete()
<__main__.Concrete object at 0x7fc935d28898>
2 of 13
152

The old-school (pre-PEP 3119) way to do this is just to raise NotImplementedError in the abstract class when an abstract method is called.

Copyclass Abstract(object):
    def foo(self):
        raise NotImplementedError('subclasses must override foo()!')

class Derived(Abstract):
    def foo(self):
        print 'Hooray!'

>>> d = Derived()
>>> d.foo()
Hooray!
>>> a = Abstract()
>>> a.foo()
Traceback (most recent call last): [...]

This doesn't have the same nice properties as using the abc module does. You can still instantiate the abstract base class itself, and you won't find your mistake until you call the abstract method at runtime.

But if you're dealing with a small set of simple classes, maybe with just a few abstract methods, this approach is a little easier than trying to wade through the abc documentation.

🌐
Python.org
discuss.python.org › typing
Calling abstract methods - Typing - Discussions on Python.org
January 6, 2024 - PEP 544 indicates that a type checker should generate an error if a class that explicitly derives from the protocol attempts to call a method through super() if that method is unimplemented in the protocol. class Proto(Protocol): def method(self) -> None: ... class Impl(Proto): def method(self) -> None: super().method() # Type checker error This makes sense because the method in the protocol is effectively abstract.
🌐
Python Course
python-course.eu › oop › the-abc-of-abstract-base-classes.php
20. The 'ABC' of Abstract Base Classes | OOP | python-course.eu
Our example implemented a case of simple inheritance which has nothing to do with an abstract class. In fact, Python on its own doesn't provide abstract classes. Yet, Python comes with a module which provides the infrastructure for defining Abstract Base Classes (ABCs).
🌐
Quora
quora.com › Is-it-possible-to-define-a-abstract-methods-without-declaring-a-abstract-class
Is it possible to define a abstract methods without declaring a abstract class? - Quora
Answer (1 of 3): Yes It is possible to define an abstract method without declaring the class abstract, It is INTERFACE An abstract method is a kind of method that is declared but having no implementation and if a class includes abstract methods, ...
🌐
Stack Overflow
stackoverflow.com › questions › 46726272 › how-to-create-abstract-classes-using-abc-without-using-an-abstract-method
python - How to create abstract classes using abc without using an abstract method? - Stack Overflow
You can. Simply inherit from ABC but don't delcare a method abstract, so it needn't be implemented in its subclasses. If you want the abstract class to enforce the implementation of all methods, decorate all methods.
Top answer
1 of 3
28

What you're trying to do will just work—but it's a very bad idea.

In general, you don't want to change the signature of a method in incompatible ways when overriding. That's part of the Liskov Substitution Principle.

In Python, there are often good reasons to violate that—inheritance isn't always about subtyping.

But when you're using ABCs to define an interface, that's explicitly about subtyping. That's the sole purpose of ABC subclasses and abstractmethod decorators, so using them to mean anything else is at best highly misleading.


In more detail:

By inheriting from Agent, you are declaring that any instance of Clever_Agent can be used as if it were an Agent. That includes being able to call my_clever_agent.perceive_world(my_observation). In fact, it doesn't just include that; that's the entirely of what it means! If that call will always fail, then no Clever_Agent is an Agent, so it shouldn't claim to be.

In some languages, you occasionally need to fake your way around interface checking, so you can later type-switch and/or "dynamic-cast" back to the actual type. But in Python, that's never necessary. There's no such thing as "a list of Agents", just a list of anything-at-alls. (Unless you're using optional static type checking—but in that case, if you need to get around the static type checking, don't declare a static type just to give yourself a hurdle to get around.)


In Python, you can extend a method beyond its superclass method by adding optional parameters, and that's perfectly valid, because it's still compatible with the explicitly-declared type. For example, this would be a perfectly reasonable thing to do:

class Clever_Agent(Agent):
    def perceive_world(self, observation, prediction=None):
        print('I see %s' % observation)
        if prediction is None:
            print('I have no predictions about what will happen next')
        else:
            print('I think I am going to see %s happen next' % prediction)

Or even this might be reasonable:

class Agent(ABC):
    @abstractmethod
    def perceive_world(self, observation, prediction):
        pass

class Dumb_agent(Agent):
    def perceive_world(self, observation, prediction=None):
        print('I see %s' % observation)
        if prediction is not None:
            print('I am too dumb to make a prediction, but I tried anyway')

class Clever_Agent(Agent):
    def perceive_world(self, observation, prediction):
        print('I see %s' % observation)
        print('I think I am going to see %s happen next' % prediction)
2 of 3
0

In many ways overriding an abstract method from a parent class and adding or changing the method signature is technically not called a method override what you may be effectively be doing is method hiding. Method override always overrides a specific existing method signature in the parent class.

You may find your way around the problem by defining a variant abstract method in your parent class, and overriding it if necessary in your sub classes.

🌐
Reddit
reddit.com › r/python › what's the point of abstract classes if they don't enforce method signatures?
r/Python on Reddit: What's the point of abstract classes if they don't enforce method signatures?
December 18, 2016 -

I was surprised to see the Python abstract classes don't enforce anything except the override and method name. I can see why in Python enforcing parameter data-types would probably not work, but the number of parameters and parameter names ought to be enforced.

I've always thought the point of abstract classes was to ensure that any inheritor of the class would would work with existing code to run the abstract methods defined in the super class. The whole point was to enforce method signatures.

It seems to me that Python's implantation of abstract classes has very little utility. Does anyone even use them? What for?

🌐
Ikriv
ikriv.com › blog
Python: the land of abstract static methods – Ivan Krivyakov
Unlike many other languages, Python allows abstract static methods (see the reference). A class directly or indirectly deriving from abc.ABC cannot be instantiated, unless all its abstract methods are redefined. This includes static methods.
🌐
CodeSignal
codesignal.com › learn › courses › revisiting-oop-concepts-in-python › lessons › understanding-abstract-classes-and-abstract-methods-in-python
Understanding Abstract Classes and Abstract Methods in ...
When you define an abstract method within an abstract class, it acts as a placeholder without any implementation, serving as a rule that subclasses must follow. These methods establish a required interface, ensuring that any subclass provides its specific implementation.
🌐
Real Python
realpython.com › ref › glossary › abstract-base-class
abstract base class (ABC) | Python Glossary – Real Python
To define an abstract base class, you inherit from abc.ABC and use the @abstractmethod decorator to mark methods that must be implemented by subclasses. Attempting to instantiate an abstract base class or a subclass that hasn’t implemented all abstract methods will raise a TypeError exception. Here’s an example of how to define and use an abstract base class in Python:
🌐
GeeksforGeeks
geeksforgeeks.org › python › abstract-classes-in-python
Abstract Classes in Python - GeeksforGeeks
This is because they contain one or more abstract methods or properties that lack implementations. Attempting to instantiate an abstract class results in a TypeError. Example: This example shows the error raised when trying to instantiate an abstract class. ... from abc import ABC, abstractmethod class Animal(ABC): @abstractmethod def make_sound(self): pass # animal = Animal() # TypeError: Can't instantiate abstract class Animal with abstract methods make_sound
Published   September 3, 2025