Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Differences in three ways to define a abstract class

I found multiple (slightly different) ways to define abstract classes in Python. I read the documentation and also could not find an answer here on stackoverflow.

The main difference between the three examples (see code below) is:

  • A sets a new metaclass abc.ABCMeta explicitly
  • B inherits from abc.ABC
  • C inherits from objects but defines @abc.abstractmethod classes

It seems that A and B are not different (i.e. also B has the new metaclass abc.ABCMeta). However, class C remains of type type.

What are the impacts of not defining a metaclass for C? When is it necessary to define the metaclass or is it wrong/bad style to not define the abc.ABCMeta metaclass for an abstract class? Nonetheless, the class C seems to behave as I expect from an ABC.

import abc

class A(metaclass=abc.ABCMeta):
    # Alternatively put __metaclass__ = abc.ABCMeta here
    @abc.abstractmethod
    def foo(self):
        raise NotImplementedError


class B(abc.ABC):

    @abc.abstractmethod
    def foo(self):
        raise NotImplementedError


class C(object):

    @abc.abstractmethod
    def foo(self):
        raise NotImplementedError


class Aimpl(A):

    def foo(self):
        print("Aimpl")


class Bimpl(B):
    def foo(self):
        print("Bimpl")


class Cimpl(C):
    #def foo(self):
     #   print("Cimpl")
     pass

Aimpl().foo()                           # Aimpl
print(isinstance(Aimpl, A))             # False
print(issubclass(Aimpl, A))             # True
print(isinstance(Aimpl, abc.ABCMeta))   # True
print(type(A))                          # <class 'abc.ABCMeta'>
print("---")

Bimpl().foo()                           # Bimpl
print(isinstance(Bimpl, B))             # False
print(issubclass(Bimpl, B))             # True
print(isinstance(Bimpl, abc.ABCMeta))   # True
print(type(B))                          # <class 'abc.ABCMeta'>
print("---")

Cimpl().foo()                           # Cimpl
print(isinstance(Cimpl, C))             # False
print(issubclass(Cimpl, C))             # True
print(isinstance(Cimpl, abc.ABCMeta))   # False
print(type(C))                          # <class 'type'>
print("---")
like image 710
no_use123 Avatar asked May 29 '18 07:05

no_use123


People also ask

What is abstract class how is it different from other methods?

Abstract class: is a restricted class that cannot be used to create objects (to access it, it must be inherited from another class). Abstract method: can only be used in an abstract class, and it does not have a body. The body is provided by the subclass (inherited from).

How do you define an abstract class?

An abstract class is a class that is declared abstract —it may or may not include abstract methods. Abstract classes cannot be instantiated, but they can be subclassed. When an abstract class is subclassed, the subclass usually provides implementations for all of the abstract methods in its parent class.

What are the differences between a class and an abstract class?

An abstract class cannot be directly instantiated using the new keyword. A concrete class can be directly instantiated using the new keyword. An abstract class may or may not contain abstract methods. A concrete class cannot contain an abstract method.


1 Answers

The abc.ABCMeta class is necessary to actually enforce the abstractmethod behaviour. Its itention is to disallow instantiation of any classes which do not implement the abstract method. The decorator itself cannot enforce that, the metaclass is enforcing the decorator upon instantiation:

class Foo:
    @abstractmethod
    def bar(self):
        pass

Foo()  # works

However:

class Foo(metaclass=ABCMeta):
    @abstractmethod
    def bar(self):
        pass

Foo()
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: Can't instantiate abstract class Foo with abstract methods bar

So, without the metaclass, the abstractmethod decorator doesn't do anything.

abc.ABC is merely a shorthand so you can do Foo(ABC) instead of Foo(metaclass=ABCMeta), that is all:

A helper class that has ABCMeta as its metaclass. With this class, an abstract base class can be created by simply deriving from ABC avoiding sometimes confusing metaclass usage [..]

https://docs.python.org/3/library/abc.html#abc.ABC

like image 141
deceze Avatar answered Sep 18 '22 11:09

deceze