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.
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?
Videos
Hello, if one finds interfaces useful in Python (>=3.8) and is convinced that static type-checking is a must, then why not ditch ABC and always use Protocols? I understand that the fundamental idea of a protocol is slightly different from an interface, but in practice, I had great success replacing abc's with Protocols without regrets.
With abc you would write (https://docs.python.org/3/library/abc.html) :
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def eat(self, food) -> float:
passWhereas with Protocols it's gonna be (good tutorial):
from typing import Protocol
class Animal(Protocol):
def eat(self, food) -> float:
...Scores in my subjective scoring system :)
| Capability | ABC | Protocols |
|---|---|---|
| Runtime checking | 1 | 1 (with a decorator) |
| Static checking with mypy | 1 | 1 |
Explicit interface (class Dog(Animal):) | 1 | 1 |
Implicit interface with duck-typing (class Dog:) | 0.5 (kind of with register, but it doesn't work with mypy yet) | 1 |
Default method implementation (def f(self): return 5) | -1 (implementations shouldn't be in the interfaces) | -1 (same, and mypy doesn't catch this) |
| Callback interface | 0 | 1 |
| Number of code lines | -1 (requires ABC inheritance and abstracmethod for every method) | 0 (optionalProtocol inheritance) |
| Total score | 1.5 | 4 |
So I do not quite see why one should ever use ABC except for legacy reasons. Other (IMHO minor) points in favour of ABC I've seen were about interactions with code editors.
Did I miss anything?
I put more detailed arguments into a Medium. There are many tutorials on using Protocols, but not many on ABC vs Protocols comparisons. I found a battle of Protocols vs Zope, but we are not using Zope, so it's not so relevant.
Hi everyone. Last time I shared a post about Interface programming using abs in Python, and it got a lot of positive feedback—thank you!
Several people mentioned protocols, so I wrote a new article exploring that topic. In it, I compare protocols with abstract base classes and share my thoughts and experiences with both. You can check it out here: https://www.tk1s.com/python/protocols-vs-abstract-base-classes-in-python Hope you'll like it! Thanks!
From the docs:
A class that has a metaclass derived from
ABCMetacannot 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
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
I an currently learning OOP in python and was struggling with abstraction. Like is it a blueprint for what the subclasses for an abstract class should have or like many definitions say is it something that hides the implementation and shows the functionality? But how would that be true since it mostly only has pass inside it? Any sort of advice would help.
Thank you
I come from a C++ background, and I need to write an abstract base class, that inherits from abc. In this abstract base class, I would like to "declare" (this is C++ lingo, but I don't think variable declaration is a thing in Python) an uninstantiated variable, say `var`, which is initialized in the subclasses.
I'm wondering if there's any way to do this in Python?
Consider the following code. Note the comments in particular:
from abc import ABC, abstractmethod
# func1 MUST be overridden
# func2 may be overridden
class Class1(ABC):
@abstractmethod
def func1(self):
pass #any code here is useless
def func2(self):
print('fallback message')
# func1, func2 may be overridden
# @abstractmethod does nothing
# Effectively same as Class3, Class4
class Class2():
@abstractmethod
def func1(self):
pass
def func2(self):
pass
# func1, func2 may be overridden
# Inheriting from ABC does nothing
# Effectively same as Class4, Class2
class Class3(ABC):
def func1(self):
pass
def func2(self):
pass
# func1, func2 may be overridden
# Effectively same as Class3, Class2
class Class4():
def func1(self):
pass
def func2(self):
pass Assuming my comments are valid, am I correct in thinking that the @abstractmethod decorator only makes sense when used in conjunction with an ABC class? (i.e., Class1)
I'm currently taking an Udemy course on classes but unfortunately the section on Abstract Classes doesn't go into a whole lot of depth. I have a few questions as well as some sample code I wrote that I'd like to make sure is properly written.
What exactly is the point of abstract classes? My first take is that it would be used in an environment where there are several developers where one may be writing the abstract class but wants to make it obvious that the child classes need specific methods/attributes. It also ensures that an instance cannot be made from the abstract class. Are they other reasons to use an abstract class that I'm not thinking of?
Googling for clarification, I've seen a couple different implementations of the abc module. What's the different of each?
MyClass(metaclass=abc.ABC): ...
MyClass(metaclass=abc.ABCMeta): ...
MyClass: __metaclass__=abc.ABCMeta ...
From what I can tell, the first example is for Python 3.4+, the second is for Python 3.0+, and the last is for Python 2.X. My confusion comes from the below example. I'm using Python 3.4 but (metaclass=abc.ABC) doesn't work while (metaclass=abc.ABCMeta) does.
3. My last question is just for a sanity check. Is the below code properly using both inheritance and abstract classes? Is there a better or more Pythonic way to do it?
from abc import ABCMeta, abstractmethod
class Vehicle(metaclass=ABCMeta):
@abstractmethod
def __init__(self, year, miles, make, model):
self.year = year
self.miles = miles
self.make = make
self.model = model
self.sold_on = None
def sold_date(self, date):
self.sold_on = date
class Car(Vehicle):
def __init__(self, year, miles, make, model):
super().__init__(year, miles, make, model)
self.wheels = 4
self.doors = 4
class Motorcycle(Vehicle):
def __init__(self, year, miles, make, model):
super().__init__(year, miles, make, model)
self.wheels = 2
self.doors = 0I am working in research where I am using python (numpy, scikit-learn, matplotlib mostly) to solve an optimization problem. I have a parent class where most of the code is, but we want to try two different methods for part of the optimization, so I have two child classes (one for each). I am using @ abstractmethod in the parent for the function, then I want to implement in the children.
The children implementations will not have the same parameters. Should I use *args and **kwargs in the parent implementation, or does it not matter and I can just do
@abstractmethod def func(self): pass
and then in the children's implementations pass whatever I need:
class Child1(Base):
def func(self, var1, var2):
do_stuffAre you using python3 to run that code? If yes, you should know that declaring metaclass in python3 have changes you should do it like this instead:
import abc
class AbstractClass(metaclass=abc.ABCMeta):
@abc.abstractmethod
def abstractMethod(self):
return
The full code and the explanation behind the answer is:
import abc
class AbstractClass(metaclass=abc.ABCMeta):
@abc.abstractmethod
def abstractMethod(self):
return
class ConcreteClass(AbstractClass):
def __init__(self):
self.me = "me"
# Will get a TypeError without the following two lines:
# def abstractMethod(self):
# return 0
c = ConcreteClass()
c.abstractMethod()
If abstractMethod is not defined for ConcreteClass, the following exception will be raised when running the above code: TypeError: Can't instantiate abstract class ConcreteClass with abstract methods abstractMethod
Import ABC from abc and make your own abstract class a child of ABC can help make the code look cleaner.
from abc import ABC, abstractmethod
class AbstractClass(ABC):
@abstractmethod
def abstractMethod(self):
return
class ConcreteClass(AbstractClass):
def __init__(self):
self.me = "me"
# The following would raise a TypeError complaining
# abstractMethod is not implemented
c = ConcreteClass()
Tested with Python 3.6
I thought I understood what abstract class means but my professor just commented that it wasn't a abstract class. What I did is essentially this:
first instruction: create an abstract base class with two int attributes then derived another class called Hero with a string attribute which stores the title "hero"
from abc import ABC
class Person(ABC):
def __init__(self, height, speed):
self.height = height
self.speed = speed
def walk(self):
//walk method
from person import Person
class Hero(Person):
def __init__(self, height, speed):
super().__init__(height, speed)
self.person_title = "Hero"
was this the right way to do it?