0

There are a few classes that I defined

class Animal:
    def do_parent_method():
        pass

class Monkey(Animal):
    pass


class Elephant(Animal):
    pass


@dataclass
class Zoo:
    monkey: Monkey= Monkey()
    elephant: Elephant = Elephant()
    start_time: datetime = None
    name: str = 'Not important at all'

    def data_format(self):
        items = [self.monkey, self.elephant]  # Now I hard code here
        for item in items:
            do_something()

The key point is about how to get attributes in the Zoo class

Maybe someday, we will add another animal in our code

@dataclass
class Zoo:
    monkey: Monkey= Monkey()
    elephant: Elephant = Elephant()
    start_time: datetime = None
    name: str = 'Not important at all'

    def data_format(self):
        items = [get the attributes that extends from Animal]  # How to do?
        for item in items:
            do_parent_method()

For now I just want items to be a list, so that I could for-loop it.

Or if you have another good idea is also good for me.

Note:

The all the attributes in Zoom class will only have some str, datetime, int type. All the other instance will be the children class of Animal class.

Fixed:

Accidentally entered 'zoo' into 'zoom'

Tony Chou
  • 584
  • 1
  • 9
  • 26
  • Does this answer your question? [How to find all the subclasses of a class given its name?](https://stackoverflow.com/questions/3862310/how-to-find-all-the-subclasses-of-a-class-given-its-name) – Pynchia Dec 04 '19 at 04:11
  • @Pynchia: I don't see how that's relevant. Simple `isinstance` checking works fine here, you don't need the exhaustive set of all subclasses to do it. – ShadowRanger Dec 04 '19 at 04:22
  • Given the OP wants all the animals, why have to instantiate a class var each by name and hard-coded? Instantiate them automatically, one per subclass and store them in the list `items = [s() for s in Animal.__subclasses__()]` – Pynchia Dec 04 '19 at 04:35

1 Answers1

1

The dataclasses.fields function can return field information about a class, including both the name and type of each field. So your list comprehension can be written:

items = [getattr(self, field.name) for field in fields(self) if issubclass(field.type, Animal)]

The flaw here is that it doesn't work for string annotations, which includes all cases where the module uses from __future__ import annotations. You could use the tricks here to resolve to the actual type, or you could just unconditionally get all the fields, then filter them with isinstance checks (that verify the runtime type, not the annotated type that can be blithely ignored at runtime):

items = [attr for attr in (getattr(self, field.name) for field in fields(self)) if isinstance(attr, Animal)]
ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • It's not clear if the OP wants the instances of the Animal subclasses to appear in the dataclass, to be used e.g. `zoom_inst.dog`. Zoom is a dataclass after all. – Pynchia Dec 04 '19 at 05:06
  • @Pynchia: Seems pretty clear. They want the dynamically generated version of `[self.monkey, self.elephant]` where it pulls whatever attributes the dataclass has that happen to be `Animal` subclasses without having to explicitly list them one by one. – ShadowRanger Dec 04 '19 at 05:08
  • Ok, then i will undelete my answer – Pynchia Dec 04 '19 at 05:11
  • @Pynchia: Your answer is *creating* a bunch of *new* instances of `Animal` subclasses, not pulling any of the *existing* `Animal` subclass instances attached as attributes to the existing instance of the `Zoom` dataclass. I'm not sure where you got the idea that creating additional instances of the subclasses makes any sense. – ShadowRanger Dec 04 '19 at 05:15
  • I understand the OP wants all the Animals. So why type them all in? Unless they also need to appear as attrs of the dataclass. And that is why I would set such names automatically if that is the case – Pynchia Dec 04 '19 at 05:20
  • @Pynchia: The title of the question literally begins "How to get attributes" (and once again mentions that they're dealing with attributes, not just random `Animal` instances in the final paragraph); of course they need to be attributes. – ShadowRanger Dec 04 '19 at 05:22
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/203566/discussion-between-shadowranger-and-pynchia). – ShadowRanger Dec 04 '19 at 05:22