1

How can I state that an abstract class variable must be defined with abcmeta.

e.g.

class AbstractMover(metaclass=ABCMeta):
    _destination_folder = NotImplementedError # how do I do something like this

    @property
    def destination_folder(self):
        return self._destination_folder

and when it's inherited, it should raise an error if the _destination_folder is not specified.

class ConcreteMover(AbstractMover): pass # should error

class ConcreteMover(AbstractMover):
    _destination_folder = "path/to/folder" # works fine

This should then let me do

>>> ConcreteMover().destination_folder
path/to/folder

BUT It should raise an error if _destination_folder is not defined in the concrete class.

A H
  • 2,164
  • 1
  • 21
  • 36
  • 2
    In this case, *just use `@abstractmethod` / `@property` / `def _destination_folder(self): pass`*. The actual implementation doesn't have to use a method or property object, the only requirement that is tested for is that the name exists. – Martijn Pieters Nov 22 '18 at 12:54
  • @MartijnPieters thanks, I'm just trying to get `mypy` & pylint off my back, it doesn't like that it's being passed a callable. – A H Nov 22 '18 at 12:56
  • 1
    Are you using Python 3.6 or newer? Then make `_destination_folder` a [variable annotation](https://www.python.org/dev/peps/pep-0526/) without a value set. – Martijn Pieters Nov 22 '18 at 13:02
  • @MartijnPieters how would that look, I currently have `@abstractmethod def _destination_folder(self) -> str: pass` and get the mypy error: `Incompatible return value type (got "Callable[[], str]", expected "str")` – A H Nov 22 '18 at 13:10
  • 1
    you forgot the `@property`, you need *both*. – Martijn Pieters Nov 22 '18 at 13:12
  • ah, that makes more sense, thanks! Works perfectly now, many thanks for your help. – A H Nov 22 '18 at 13:13
  • @MartijnPieters What is the purpose of the `@property` decorator? Couldn't it simply be omitted without cancelling the _abstractness_? Where did that idea come from? – 303 Oct 23 '21 at 20:52
  • @303: sure you can, but then you defined a method, not an attribute. Other tools that look at the ABC, like a language server for an IDE like Visual Studio Code then tell the developer to use a call instead of referencing the attribute. – Martijn Pieters Oct 29 '21 at 11:53
  • @MartijnPieters Ah, that seems to make a lot of sense. The only problem with using the `@property` decorator is that you can't provide a default value that the derived class can use. While not all too common, such a [scenario](https://stackoverflow.com/a/39388910/7107236) is still viable. What would be the most suitable workaround? Add a `@staticmethod` decorator instead? Or use a custom `@classproperty` like [this](https://stackoverflow.com/a/3203659/7107236)? – 303 Oct 29 '21 at 20:09
  • @303: just have the property return the default value! – Martijn Pieters Jan 19 '22 at 00:23
  • I think it should be `@property` / `@abstractmethod` / `def _destination_folder(self):`. The order matters. (https://github.com/python/cpython/issues/60471) – Jérôme Apr 19 '22 at 13:30

0 Answers0