What does the Abstract Base Class register method actually do in Python?
Question:
I am confused about the ABC register method.
Take the following code:
import io
from abc import ABCMeta, abstractmethod
class IStream(metaclass=ABCMeta):
@abstractmethod
def read(self, maxbytes=-1):
pass
@abstractmethod
def write(self, data):
pass
IStream.register(io.IOBase)
f = open('foo.txt')
isinstance(f, Istream) # returns true
When you register io.IOBase what exactly happens? Are you saying that IOBase class can only have methods defined by Istream ABC class going forward? What is the benefit of ABC registering other classes?
Answers:
It simply makes issubclass(io.IOBase, IStream)
return True
(which then implies that an instance of io.IOBase
is an instance of IStream
). It is up to the programmer registering the class to ensure that io.IOBase
actually conforms to the API defined by IStream
.
The reason is to let you define an interface in the form of IStream
, and let you indicate that a class that may not have actually inherited from IStream
satisfies the interface. Essentially, it is just formalized duck typing.
For example, we can replace Cat
class extending Animal
class below:
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def sound(self):
pass
# ↓↓↓ Here ↓↓↓
class Cat(Animal):
def sound(self):
print("Meow!!")
# ↑↑↑ Here ↑↑↑
print(issubclass(Cat, Animal))
With this code having register() below:
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def sound(self):
pass
# ↓↓↓ Here ↓↓↓
class Cat:
def sound(self):
print("Meow!!")
Animal.register(Cat)
# ↑↑↑ Here ↑↑↑
print(issubclass(Cat, Animal))
Then, both of the code above outputs the same result below showing Cat
class is the subclass of Animal
class:
True
I am confused about the ABC register method.
Take the following code:
import io
from abc import ABCMeta, abstractmethod
class IStream(metaclass=ABCMeta):
@abstractmethod
def read(self, maxbytes=-1):
pass
@abstractmethod
def write(self, data):
pass
IStream.register(io.IOBase)
f = open('foo.txt')
isinstance(f, Istream) # returns true
When you register io.IOBase what exactly happens? Are you saying that IOBase class can only have methods defined by Istream ABC class going forward? What is the benefit of ABC registering other classes?
It simply makes issubclass(io.IOBase, IStream)
return True
(which then implies that an instance of io.IOBase
is an instance of IStream
). It is up to the programmer registering the class to ensure that io.IOBase
actually conforms to the API defined by IStream
.
The reason is to let you define an interface in the form of IStream
, and let you indicate that a class that may not have actually inherited from IStream
satisfies the interface. Essentially, it is just formalized duck typing.
For example, we can replace Cat
class extending Animal
class below:
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def sound(self):
pass
# ↓↓↓ Here ↓↓↓
class Cat(Animal):
def sound(self):
print("Meow!!")
# ↑↑↑ Here ↑↑↑
print(issubclass(Cat, Animal))
With this code having register() below:
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def sound(self):
pass
# ↓↓↓ Here ↓↓↓
class Cat:
def sound(self):
print("Meow!!")
Animal.register(Cat)
# ↑↑↑ Here ↑↑↑
print(issubclass(Cat, Animal))
Then, both of the code above outputs the same result below showing Cat
class is the subclass of Animal
class:
True