Search code examples
pythonpython-3.xoopinheritanceabstract-class

How to declare instance variables in abstract class?


class ILinkedListElem:
    @property
    def value(self):
        raise NotImplementedError

    @property
    def next(self):
        raise NotImplementedError


class ListElem(ILinkedListElem):
    def __init__(self, value, next_node=None):
        self.value = value
        self.next = next_node

I wanna something like this. This abstract variables definition works for class vars, but not for instance

I want to all instances of ILinkedListElem subclass must has "value" and "next" attributes


Solution

  • If you want to force/require all instances of any subclass of ILinkedListElem to have the attributes "value" and "nxt", the following standard implementation with abstractmethod seems to do what you're after:

    from abc import ABC, abstractmethod
    
    class ILinkedListElem (ABC):
        @property
        @abstractmethod
        def value(self):
            raise NotImplementedError
    
        @property
        @abstractmethod
        def nxt(self):
            raise NotImplementedError
    

    This is the abstract class, from which we create a compliant subclass:

    class ListElem_good (ILinkedListElem):
        
        def __init__(self, value, next_node=None):
            self._value = value
            self._nxt = next_node
            
        @property
        def value(self):
            return self._value
        
        @property
        def nxt(self):
            return self._nxt
    

    We create an instance of this compliant subclass and test it:

    x = ListElem_good('foo', 'bar')
    print (x.value)
    print (x.nxt)
    
    #result:
        # foo
        # bar
    

    If we create a non-compliant subclass that omits an implementation of nxt, like so:

    class ListElem_bad (ILinkedListElem):
        
        def __init__(self, value):
            self._value = value
            
            
        @property
        def value(self):
            return self._value
    

    when we try to create an instance of this non-compliant subclass:

    y = ListElem_bad('foo')
    print (y.value)
    

    it fails:

        y = ListElem_bad('foo')
    
    TypeError: Can't instantiate abstract class ListElem_bad with abstract methods nxt
    

    This relies on essentially the same solution offered here, which you suggested in a comment-exchange does not meet your requirements. But when applied to your specific use-case above, it appears to precisely address the issue you've raised - or have I misunderstood?