Skip to main content
added 12 characters in body
Source Link
jfaccioni
  • 516
  • 2
  • 8

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.

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__(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__(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.

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.

Source Link
jfaccioni
  • 516
  • 2
  • 8

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__(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__(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.