SubQuery is an abstract base class (per the abc module) with one or more abstract methods that you did not override. By adding ABC to the list of base classes, you defined ValueSum itself to be an abstract base class. That means you aren't forced to override the methods, but it also means you cannot instantiate ValueSum itself.
PyCharm is warning you ahead of time that you need to implement the abstract methods inherited from SubQuery; if you don't, you would get an error from Python when you actually tried to instantiate ValueSum.
As to what inheriting from ABC does, the answer is... not much. It's a convenience for setting the metaclass. The following are equivalent:
class Foo(metaclass=abc.ABCMeta):
...
and
class Foo(abc.ABC):
...
The metaclass modifies __new__ so that every attempt to create an instance of your class checks that the class has implemented all methods decorated with @abstractmethod in a parent class.
Understanding abc.ABC
What's the point of ABC & @abstractmethod
Interfaces with Protocols: why not ditch ABC for good?
Python Collections Library Abstract Base Class (ABC) Question
Videos
SubQuery is an abstract base class (per the abc module) with one or more abstract methods that you did not override. By adding ABC to the list of base classes, you defined ValueSum itself to be an abstract base class. That means you aren't forced to override the methods, but it also means you cannot instantiate ValueSum itself.
PyCharm is warning you ahead of time that you need to implement the abstract methods inherited from SubQuery; if you don't, you would get an error from Python when you actually tried to instantiate ValueSum.
As to what inheriting from ABC does, the answer is... not much. It's a convenience for setting the metaclass. The following are equivalent:
class Foo(metaclass=abc.ABCMeta):
...
and
class Foo(abc.ABC):
...
The metaclass modifies __new__ so that every attempt to create an instance of your class checks that the class has implemented all methods decorated with @abstractmethod in a parent class.
The 'Abstract Base classes" or abc.ABC is a helper class
https://docs.python.org/3/library/abc.html
Here's a snippet of why they exist:
The collections module has some concrete classes that derive from ABCs; these can, of course, be further derived. In addition, the
collections.abcsubmodule has some ABCs that can be used to test whether a class or instance provides a particular interface, for example, if it is hashable or if it is a mapping.
A good example here: https://pymotw.com/2/abc/ | https://pymotw.com/3/abc/
From pymotw:
Forgetting to set the metaclass properly means the concrete implementations do not have their APIs enforced. To make it easier to set up the abstract class properly, a base class is provided that sets the metaclass automatically.
abc_abc_base.py
import abc
class PluginBase(abc.ABC):
@abc.abstractmethod
def load(self, input):
"""Retrieve data from the input source
and return an object.
"""
@abc.abstractmethod
def save(self, output, data):
"""Save the data object to the output."""
class SubclassImplementation(PluginBase):
def load(self, input):
return input.read()
def save(self, output, data):
return output.write(data)
if __name__ == '__main__':
print('Subclass:', issubclass(SubclassImplementation,
PluginBase))
print('Instance:', isinstance(SubclassImplementation(),
PluginBase))
I am being asked to maintain code that subclasses from abc.ABC. I have read the python documentation, the associated PEP, and even visited pymotw. I do not understand what abstract classes give you.
If I have class A and then I derive subclass B from it wouldn't issubclass(B,A) still be true?
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.