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->VehicleFoo->CarBar->TruckThing->GarageThingFoo->CarGarageThingBar->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.