Python proper abstract class and subclassing with attributes and methods

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")


I don't see much of problems with using properties as abstract attributes e.g:

class Foo(abc.ABC):
@property
@abc.abstractmethod
def bar(self):
...


However, if you still don't like it instead of going for your ninja stackoverflow way there is an easy way in python 3.6.

class Foo(abc.ABC):
def __init_subclass__(cls, **kwargs):
if not hasattr(cls, 'bar'):
raise NotImplementedError('damn')
return super().__init_subclass__(**kwargs)


As for one instance per class just look for python Singleton implementations.

• This (stackoverflow.com/a/33201/2381631) one seems to work for the singleton part. However, your __init_subclass__ throws an AttributeError: 'super' object has no attribute '_Base__init_subclass using Python 3.6. Jan 24 '17 at 17:16
• By the way, the reason for not having properties as abstract attributes is to avoid having the need to implement them all (and type a lot) in subclasses. Simply attr1 = something is way easier and straightforward right after the declaration of the class class Sub(Base): .... Jan 24 '17 at 17:20
• @dfernan I forgot trailing __ fixed AttributeError. as for property with abstractmethod since those 2 are functions you can create your custom abstract_property function using those 2.
– Alex
Jan 24 '17 at 17:34
• Seems to work well now, thanks. This indeed looks like the cleaner option. Jan 24 '17 at 18:09