vanPelt2
vanPelt2

Reputation: 898

Ensure abstract Python method is implemented as a class method (or not)

I have an abstract Python class (v3.8.10) with two abstract methods, save() and load().

import abc

class Parent(abc.ABC):

    @abc.abstractmethod
    def save(*args, **kwargs):
        pass

    @abc.abstractmethod
    def load(*args, **kwargs):
        pass

The purpose of writing such a class is typically to establish an API for downstream development: if you want to inherit from this class, you have to implement save() and load(). Now the questions:

These would be additional API constraints required by class Parent. For example, the following class is instantiable, because it implements save() and load():

class GoodChild(Parent):

    def save(self, savefile):
        """Save instance-specific data to a file."""
        print(f"saving data to {savefile}")
        # ...

    @classmethod
    def load(cls, loadfile):
        """Load data from a file, creating an instance."""
        print(f"loading data from {loadfile}")
        # ...
        # return cls(data)

But is it possible to write Parent.save() and Parent.load() in such a way that the following classes are not instantiable?

class BadChild(Parent):

    def save(self, savefile):
        print("This is fine.")

    def load(self, loadfile):
        print("Uh oh, this should be a class method!")


class NaughtyChild(Parent):

    @classmethod
    def save(cls, savefile):
        print("Uh oh, this shouldn't be a class method!")

    @classmethod
    def load(cls, loadfile):
        print("This is fine.")
>>> papa = Parent()
TypeError: #Can't instantiate abstract class Parent with abstract methods load, save

# Can instantiate this class.
>>> child_1 = GoodChild()

# But can also instantiate these. Can we modify Parent so that these raise TypeError?
>>> child_2 = BadChild()
>>> child_3 = NaughtyChild()

Or, if you think such a requirement would be a really bad idea, why?

Upvotes: 2

Views: 705

Answers (1)

Lenormju
Lenormju

Reputation: 4368

Yes and no. In Python, many things are possible, but some are very inconvenient.

Why would you want to prevent implementations to use classmethod ? You did not said what load should do, or of what type are its arguments. And it does not make much sense from the Python data model point of view.

But if you really want, that's what typing is for in Python : check that something conforms to the expected signature. Even so, having either one of the two methods classmethod but not the other is quite difficult to express, if not just impossible.
So let me ask you a question : is it really a problem that there are some classmethods ? You can't know how the abstract methods will be implemented.
And are staticmethods a problem too ?
If so, Python may not be the language to craft such rigid contracts.

Upvotes: 2

Related Questions