25

Is there a way to declare an abstract instance variable for a class in python?

For example, we have an abstract base class, Bird, with an abstract method fly implemented using the abc package, and the abstract instance variable feathers (what I'm looking for) implemented as a property.

from abc import ABCMeta, abstractmethod

class Bird(metaclass=ABCMeta):

    @property
    @abstractmethod
    def feathers(self):
        """The bird's feathers."""

    @abstractmethod
    def fly(self):
        """Take flight."""

The problem is that Eagle, a class derived from Bird, is required to have feathers implemented as a property method. So the following is not an acceptable class, but I'd like it to be

class Eagle(Bird):

    def __init__(self):
        self.feathers = 'quill'

    def fly(self):
        print('boy are my arms tired')

There might be a problem since the requirement is on the instance itself, and really after its instantiation, so I don't know if things like the abc package will still work.

Are there some standard ways of handling this?

2
  • Maybe I missed the point. Can you shortly explain why do you need an abstract property? Otherwise just let it be a normal property. Commented Jun 27, 2018 at 6:31
  • 1
    I'd like it to be enforced, so that if Eagle instances don't have a feathers attribute, a helpful error is raised (to avoid unpredictable behavior). (If you meant more specifically, sorry but it's hard to answer, since I was hoping to use this for several different variables.) Commented Jun 27, 2018 at 6:34

2 Answers 2

13

The abc system doesn't include a way to declare an abstract instance variable. The code that determines whether a class is concrete or abstract has to run before any instances exist; it can inspect a class for methods and properties easily enough, but it has no way to tell whether instances would have any particular instance attribute.

The closest thing is probably a variable annotation:

class Bird(metaclass=ABCMeta):
    feathers : str
    ...

abc won't do anything with that annotation, but it at least expresses to readers and static type checkers that instances of Bird are supposed to have a feathers instance variable. (Whether static type checkers will understand that this instance variable is supposed to come from subclasses, I don't know.)

Sign up to request clarification or add additional context in comments.

Comments

11

Something simple like the following can work, using a common property:

class Bird(object):
    @property
    def feathers(self):
        try:
            return self._feathers
        except AttributeError:
            raise WhateverError('No feathers')  # maybe obfuscate inner structure

class Eagle(Bird):
    def __init__(self):
        self._feathers = 'quill'

>>> Bird().feathers
WhateverError: No feathers
>>> Eagle().feathers
'quill'

1 Comment

I would add that Bird._init__ should make the actual assignment, and that Eagle.__init__ should simply call super().__init__('quill') to provide the value for the assignment. _feathers is an implementation detail of the property defined by Bird.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.