2

I have a certain class, namely Animal, and several subclasses like Dog, Cow, Lion, etc.

Animal is an abstract class which has an abstract static method eats(Food f).

All of these subclasses implement eats and, according to each animal, will either return True or False.

How can I iterate through each of those and create a new Animal whose type eats that specific food without manually typing each class?

For example, I'd like to get an object of type Animal that eats grass, without actually creating a new Cow.

Finding the subclasses of Animal may be one part, but I am more interested in actually iterating some sort of list of classes and running eats on each of them, until I find one that returns True and then create a new object of that class.

Thanks.

wtf8_decode
  • 452
  • 6
  • 19
  • *“How can I iterate through each of those”* – Iterate through what? A list of foods, or a list of animals? What exactly do you want to create? New animal types? Or do you just want to collect those animal types that eat a certain kind of food? – poke Nov 15 '15 at 21:37
  • I had a really hard time explaining my question... I'd like to get a new Cow if the food is grass, without actually typing Cow. I would need to somehow iterate through each subclass of `Animal` and pick the one that makes `eats(grass)` true (I think). – wtf8_decode Nov 15 '15 at 21:40
  • How do you want to get a new `Cow` without actually creaing a new `Cow`? You are contradicting yourself. Do you mean "without explicitly creaing a new `Cow`"? – glglgl Nov 15 '15 at 21:41
  • 1
    Possible duplicate of [How can I find all subclasses of a given class in Python?](http://stackoverflow.com/questions/3862310/how-can-i-find-all-subclasses-of-a-given-class-in-python) – personjerry Nov 15 '15 at 21:42
  • I actually think it's more than just that, because I also need to run `eats` on each class and do a `newObj = ...` – wtf8_decode Nov 15 '15 at 21:43

1 Answers1

4

You could iterate over all subclasses, do the checks and then get the first one which matches:

def create_animal_eating(food):
    gen = (subclass for subclass in Animal.__subclasses__() if subclass.eats(food))
    subclass = next(gen, None)
    if subclass is None:
        raise ValueError("No animal eats " + repr(food))
    new_obj = subclass()

This essentially does exactly what you describe and thus doesn't need any explanation.

But it gets only the immediate subclasses; if you really need all subclasses no matter how deep they are nested, refer to the linked article.

glglgl
  • 89,107
  • 13
  • 149
  • 217