1

I have a base class with function run. For example:

class A:
    @abstractmethod
    def run(self, steps):
        ...

It is possible to define class B with more arguments to the run method.

class B(A):
    def run(self, steps, save):
        ...

Working with typing, I can specify if a function gets either A or B as argument. By specifying the function gets A, I tell that I only need the basic interface of run. While specifying B says I need the extended one.

The purpose of this design is to declare a base interface that all the children share but each one can have an extended API.

This is impossible to be done in other languages. Hence I wonder, is it an anti-pattern? Is it something legit to do?

5
  • Do you use super().run(steps) in your class B? Commented Nov 21, 2022 at 9:16
  • If class A has an abstract method this cannot be instatiated Commented Nov 21, 2022 at 9:26
  • @LucasM.Uriarte I don't get an instance of A, the typing says i get a base class of A. Commented Nov 21, 2022 at 9:27
  • in that case is run a static method? Do you acces to attributes using self.attr inside the run method? If not you could used a protocol intead of an abstract class Commented Nov 21, 2022 at 9:42
  • I know what you do in your function would be something like def function(api: A): but later when you execute the function you would need an instance. Commented Nov 21, 2022 at 9:44

1 Answer 1

1

In Python you can do something like the following.

class A:

  def run(self, steps):
    print("Using class A's run.")
    print(f"steps are {steps}")


class B(A):

  def run(self, steps, other_arg=None):
    if other_arg:
      print("Using class B's override.")
      print(f"steps are {steps}")
    else:
      # Use parent's run logic instead.
      super().run(steps)

x = B()
x.run(100)
x.run(30, other_arg="something")

# Using class A's run.
# steps are 100
# Using class B's override.
# steps are 30

Now, should you do this? There is a time and a place. You can get into trouble as well. Imagine you break the interface of the core object you're inheriting from, so the core object loses its abstraction value. You'd have been better off having two objects or rewriting your abstraction to be more robust to the differences in object you wish you represent.

Edit: Note that the original question changed to make the base run method abstract. The solution posted here is mostly invalidated by that.

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

2 Comments

How would your answer change if the base method is abstract? The purpose is to declare a base interface which all the base classes implement but each one can have more parameters.
Yeah, this gets into the interface breakage part of my answer. The technical answer might be to add *args and **kwargs to your original base method's signature for that flexibility, but you might want to think more about if your abstraction is at the right level. Should the base class perhaps take a configuration payload and handle it, or similar? Should the base class be broken in multiple classes? That's for you to explore :)

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.