The idea behind Abstract Base Classes is that they can't be instantiated by themselves, only their subclasses can. However, we would still use
__init__ to ensure that attributes of class instances are set properly. In your case, that would be both
If that is all that is needed in a constructor, then subclasses don't even need to provide their own constructor. Calling
__init__ in that case redirects to the base class' implementation. Otherwise, remember to call
super().init() to explicitly call the superclass constructor.
Coupling the class name with the instance attribute __name
self.__name = self.__class__.__name__ is a bad practice. There is no reason why they should be coupled - and you're defining a setter so that coupling can fall apart later.
A better idea would be to ask for the currency name in the constructor of the base class. Then, in subclasses, we would call
super().__init__() by providing a string as the currency name. This enables you to change the
_name attribute without changing the class names of the subclasses.
Also, a side note: there is a typo when setting
_name (note the double underscore)!
Name Property Getter and Setter
Here, you provide a default for both implementations. Note that you haven't defined any of them as
abc.abstractmethod (link), indicating that subclasses need not override them. Classes inheriting from ABC cannot be instantiated unless all abstract methods or properties are implemented. However, since you provided implementations for all methods,
BaseCurrency can be instantiated.
In addition the name setter explicitly checks the
_name attribute of the instance to avoid the setter to be called. This puts a cognitive load on you to change the condition if you ever change the
BaseCurrency to be called something else.
Thankfully, there is an easy fix for both of these - declare the setter as an abstract method:
def name(self, name : str):
Since you have an abstract method now,
BaseCurrency cannot be instantiated. Also, subclasses need to implement their own name setter which eliminates the need to check if the calling class is the base one.
This also means you actually need to provide a body to the
Dirham class. Usually, empty subclasses of an abstract class tell you either you don't need an abstract class (everything can be done through instantiation) or you are doing too much in the abstract class that should be left to the subclasses. And an abstract class with no abstract methods (that is, without places that need to be filled in for the class to do something) is abstract only in name.