-1

Say I have two object types of the same interface MyObj (I am using python in this project so I will use the same for the explanation)

class Foo(MyObj): a = [5, 10] class Bar(MyObj): a = [[1, 2], [3, 4]] 

Now I have this other class to do something with MyObj objects. Doing this is almost exactly the same for both Foo and Bar type of objects. However, an intermediate step of this process requires different attributes for Foo and Bar

class Thing: needed_func: Callable # This function does something with the variable `a` def __init__(self, o: MyObj): """Initialization which is the same for Foo and Bar""" def do_the_thing(): """steps to do the thing which is the same for both Foo and Bar""" # Here I need to use the `needed_func` class ThingFoo(Thing): needed_func = func_for_foo # takes a 1D array as input class ThingBar(Thing): needed_func = func_for_bar # takes a 2D array as input 

When I have the Thing.do_the_thing implementation, I only need the two line implementations of the ThingFoo and ThingBar implementations to work with Foo and Bar objects. Since I do not need to override the __init__ in the subclasses, both Thing's subclasses will accept any MyObj's subclasses which is bad design.

How should I structure my code such that ThingFoo and ThingBar only accept the respective objects?


TL;DR

Obviously I can implement init functions in the subclasses as follows. I am asking it there is a better way?

class ThingFoo(Thing): needed_func = func_for_foo # takes a 1D array as input def __init__(self, o: Foo): super().__init__(o) class ThingBar(Thing): needed_func = func_for_bar # takes a 2D array as input def __init__(self, o: Bar): super().__init__(o) 
5
  • 1
    Are you looking for generic types?CommentedSep 28, 2021 at 12:32
  • 1
    Is there a reason that you are using o instead of the standard self here? I think it's highly advisable to stick to the norm unless you have a very good reason.CommentedSep 28, 2021 at 15:47
  • @JimmyJames My bad. I forgot the self. Corrected
    – doca
    CommentedSep 29, 2021 at 9:22
  • I would like to know the reason for the down vote as well if possible. I was hoping the question was clear enough
    – doca
    CommentedSep 29, 2021 at 9:29
  • 1
    @TeshanShanukaJ A lot of perfectly good questions attract a downvote or two right after they are posted. Don't worry about it.CommentedSep 29, 2021 at 15:20

1 Answer 1

1

Just because the __init__ method looks the same for ThingFoo and ThingBar, doesn't mean that you should avoid writing them at all costs. DRYing your code only makes sense if the code has duplicated functionality, not similar appearance.

To make this point clear, let's rename your classes for a moment:

  • MyObj -> Vehicle
  • Foo -> Car
  • Bar -> Truck
  • Thing -> Garage
  • ThingFoo -> CarGarage
  • ThingBar -> TruckGarage

Theoretically, a Garage is able to work with any kind of Vehicle. But CarGarage and TruckGarage are meant to work with a specific type of Vehicle - Car and Truck, respectively. This restriction should be reflected in the code,

Assuming this analogy to be valid in your case, I would write:

class ThingFoo(Thing): needed_func = func_for_foo # takes a 1D array as input def __init__(self, o: Foo): if not isinstance(o, Foo): raise TypeError("o is not an instance of Foo") super().__init__(o) class ThingBar(Thing): needed_func = func_for_bar # takes a 2D array as input def __init__(self, o: Bar): if not isinstance(o, Bar): raise TypeError("o is not an instance of Bar") super().__init__(o) 

Yes, the code in ThingFoo.__init__ and ThingBar.__init__ is apparently "duplicated", but it serves a purpose: it checks if the correct Vehicle has been put in the appropriate Garage. Generic things that Garages do to Vehicles are then delegated to the parent class through the super().__init__ call.

1
  • This explanation is exactly what I was looking for. (An exception is not necessary in my case, I'll stick with the typing for o in the __init__)
    – doca
    CommentedSep 29, 2021 at 9:27

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.