简体   繁体   中英

Creating objects of derived class in base class - python

I have an abstract class called IDataStream and it has one method. I create two implementations for this abstract class called IMUDataStream, GPSDataStream. In future there is a possibility that I may add another implementation of IDataStream abstract class. I have another class called DataVisualizer that visualizes all the data pulled by different DataStream classes.

In future if I add another DataStream implementation of the IDataStream abstract class, I should not be modifying the DataVisualizer class to visualize the data. Is there a way to create objects of all the derived classes of the IDataStream class, add it to a list and iterate through the list and use it to call the methods that will give me the data ?

Please note that I'm new to python and design patterns. Trying to learn. This may be a complete dumb question and total madness. I actually have a requirement for this. If this can be achieved through a design pattern I request the reader to point me to the material. Help much appreciated. Thanks !

#!/usr/bin/env python3

from abc import ABC, abstractmethod

class IDataStream(ABC):
    def get_data(self):
        pass           

class IMUDataStream(IDataStream):
    def __init__(self):
        self.__text = "this is IMU data"

    def get_data(self):
        print(self.__text)

class GPSDataStream(IDataStream):
    def __init__(self):
        self.__text = "this is GPS data"

    def get_data(self):
        print(self.__text)

class DataVisualizer:
    def __init__(self):
        # somehow create objects of all derived classes of IDataStream here and call the get_data() function
        # even if I add another derived class in the future. I should not be modifying the code here

What you're asking is to be able to find all instantiated objects that are in memory, and then filter them for only a particular class/subclass/parent class/whatever, take a look at this stack-overflow question regarding how to get all current objects and methods from memory.

That said... Any time you have to ask yourself how to find ALL instances of something GLOBALLY in memory, you should be stopping yourself and asking (which it seems like you did, so kudos) is there a better/easier way?

Most of the time, you'd want to make a data visualizer independent, such that it only consumes the data stream (which is specified during construction), see below:

ds = myDataStream()

vis = myDataVisualizer(ds)
vis.show() # or whatever

or

ds = myDataStream()

vis = myDataVisualizer()
vis.show(ds)

If you want your data visualizer to be data agnostic, at runtime (like have data coming from multiple sources), then you have a couple choices. Add methods for removing and adding data sources, or, you can link them together using something like the producer-consumer pattern using Queues and Processes (This is how I do it).

BUT, if you really must be managing your own memory, entirely (like through a map, or heap, or whatever). Then there are design patterns that can help you:

  • Factory
  • Abstract Factory
  • Decorator
  • Or maybe some other one, look at the catalog at refactoring.guru

First, you probably want method get_data to return data rather than print it (else it is doing its own visualization). This may do what you want. The following code will figure out all the subclassess of IDataStream , instantiate an instance of the class if it is not an abstract class, call method get_data on the instance and append the return values in a list :

#!/usr/bin/env python3

from abc import ABC, abstractmethod

class IDataStream(ABC):
    @abstractmethod # you probably ment to add this
    def get_data(self):
        pass

class IMUDataStream(IDataStream):
    def __init__(self):
        self.__text = "this is IMU data"

    def get_data(self):
        return self.__text

class GPSDataStream(IDataStream):
    def __init__(self):
        self.__text = "this is GPS data"

    def get_data(self):
        return self.__text


def is_abstract(cls):
    return bool(getattr(cls, "__abstractmethods__", False))


def get_all_non_abstract_subclasses(cls):
    all_subclasses = []
    for subclass in cls.__subclasses__():
        if not is_abstract(subclass):
            all_subclasses.append(subclass)
        all_subclasses.extend(get_all_non_abstract_subclasses(subclass))
    return all_subclasses


class DataVisualizer:
    def __init__(self):
        data =  [cls().get_data() for cls in get_all_non_abstract_subclasses(IDataStream)]
        print(data)

dv = DataVisualizer()

Prints:

['this is IMU data', 'this is GPS data']

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM