The goal of the code below is to have an abstract base class that defines simple methods and attributes for the subclasses. This is part of an application that provides the code base for others to develop their own subclasses such that all methods and attributes are well implemented in a way for the main application to use them. The application shall never create more than one object of each subclass, since they are supposed to implement everything correctly to be called upon. Ideally, instantiating objects of the subclasses would not even be necessary, but is needed as it is in order to check if the abstract methods are implemented.
However, Python seems to be different and awkward when it comes to classes in comparison with other programming languages (initialization, attributes, properties), and I am not very sure if the solution below is the most appropriate. It seems too much complicated to achieve the aforementioned purpose. In addition, another function (not in the code below) must be made to properly check (make sure that they are of a certain type) the attributes of the subclasses.
Any thoughts?
from abc import ABC, abstractmethod
class abstract_attribute(object):
"""taken from http://stackoverflow.com/questions/32536176/how-to-define-lazy-variable-in-python-which-will-raise-notimplementederror-for-a/32536493#32536493"""
def __get__(self, obj, type):
# Now we will iterate over the names on the class,
# and all its superclasses, and try to find the attribute
# name for this descriptor
# traverse the parents in the method resolution order
for cls in type.__mro__:
# for each cls thus, see what attributes they set
for name, value in cls.__dict__.items():
# we found ourselves here
if value is self:
# if the property gets accessed as Child.variable,
# obj will be done. For this case
# If accessed as a_child.variable, the class Child is
# in the type, and a_child in the obj.
this_obj = obj if obj else type
raise NotImplementedError(
"%r does not have the attribute %r "
"(abstract from class %r)" %
(this_obj, name, cls.__name__))
# we did not find a match, should be rare, but prepare for it
raise NotImplementedError(
"%s does not set the abstract attribute <unknown>", type.__name__)
class Base(ABC):
# attr1 and attr2 must be properly (be of a certain type) implemented by subclasses
# abstract_attribute() checks if the attribute is present in the subclass
attr1 = abstract_attribute()
attr2 = abstract_attribute()
@abstractmethod
def method():
pass
# a class property that does not change from instance to instance
@property
def prop(self):
return self.prop
@prop.setter
@classmethod
def prop(self, prop):
self.prop = prop
class Sub(Base):
# attr1 and attr2 must be implemented otherwise and exception is thrown upon accessing them
attr1 = something
attr2 = somethingElse
# method must be implemented otherwise an exception is thrown upon instantiation
def method():
print("must be implemented by subclasses")