Search code examples
pythonabc

How can I combine abc.abstractproperty with a classmethod to make an "abstract class property"?


I'd like to create a "class property" that is declared in an abstract base class, and then overridden in a concrete implementation class, while keeping the lovely assertion that the implementation must override the abstract base class' class property.

Although I took a look at this question my naive attempt to re-purpose the accepted answer didn't work:

>>> import abc
>>> class ClassProperty(abc.abstractproperty):
...     def __get__(self, cls, owner):
...             return self.fget.__get__(None, owner)()
...
>>> class Base(object):
...     __metaclass__ = abc.ABCMeta
...     @ClassProperty
...     def foo(cls):
...             raise NotImplementedError
...
>>> class Impl(Base):
...     @ClassProperty
...     def foo(cls):
...             return 5
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/2rs2ts/src/myproj/env/lib/python2.7/abc.py", line 94, in __new__
    value = getattr(cls, name, None)
  File "<stdin>", line 3, in __get__
TypeError: Error when calling the metaclass bases
    unbound method foo() must be called with Impl instance as first argument (got nothing instead)

I'm a little lost on what I should be doing. Any help?


Solution

  • You need to use this in addition to the @classmethod decorator.

    class Impl(Base):
        @ClassProperty
        @classmethod
        def foo(cls):
            return 5
    
    In [11]: Impl.foo
    Out[11]: 5