0

I have a Python class called FunctionsManager; its __init__() method is the following:

class FunctionsManager:

    def __init__(self, instance_class1, instance_class2, ..., instance_classN):
        self.__instance_class1 = instance_class1
        self.__instance_class2 = instance_class2
        ...
        self.__instance_classN = instance_classN

At the moment the value of N is 8, but with this architecture its value increases every time I have to develop a new specification.

The reason why in the class FunctionsManager there are many attributes initialized by the __init__() method it is that in the class there are 2 methods with the following structure:

class FunctionsManager:
   ...
   # this method manages the data received from a caller, and depending
   # on the value received it uses one of the instance attribute
   def handle_received_data(self, data):
       if data[0] == 1:
           result = self.__instance_class1.handle(data)  
       elif data[0] == 2:
           result = self.__instance_class2.handle(data)
       ...
       elif data[0] == N:
           result = self.__instance_classN.handle(data)
       return result

   # this method by the attributes instance check if there new data to send and 
   # prepares this data to return them to the caller; it uses one of the instance attribute     
   def prepare_data(self):
       if self.__instance_class1.data_ready():
           data = self.__instance_class1.get_data()  
       elif self.__instance_class2.data_ready():
           data = self.__instance_class2.get_data()  
       ...
       elif self.__instance_classN.data_ready():
           data = self.__instance_classN.get_data()  
       return data

In my opinion the structure of this part of the project does not conform to correct object-oriented programming, but I don't know how to change it.
To be more precise my goal is to modify the project to reduce the number of instances used to create an instance of the class FunctionsManager.

4
  • 1
    There's something inherently messed up with this design. The prepare_data() runs over those instances, in order, and checks data_ready(). I assume there is some other concurrent "process" that prepares the data? Because if that call is blocking, then it will always returns the first instance. If it is not, then there is no fallback (what if none of them have data ready?). More importantly, it sounds like you start concurrent tasks, and then gather results? If so, then I would strongly advice redesigning this. Perhaps by using async with gather. Commented Oct 22 at 9:15
  • Thank you for the suggestion I'll try to follow it and revise my project. Commented Oct 22 at 9:31
  • 1
    You wouldn't have to write that init method if you use dataclasses (but I agree with the answers that your underlying problem is on the design level) Commented Oct 23 at 6:59
  • Hi @amon. Thank you very much. I'll evalute if transform at least FunctionsManager to a dataclass. I have read the dataclasses documentation. I didn't know it. Commented Oct 23 at 7:54

2 Answers 2

1

The answer by @Caleth shows nicely how to reduce the instance variables in FunctionsManager. To also reduce the argument list when creating a FunctionsManager object, you can turn the creation logic around and let each instance_class register itself with the FunctionsManager.

class FunctionsManager:
    def __init__(self):
        self.__instances = []
    def handle_received_data(self, data):
        index = data[0]
        return self.__instances[index].handle(data)
    def prepare_data(self):
        for instance in self.__instances:
            if instance.data_ready():
                return instance.get_data()
    def register_instance(self, index, instance):
        self.__instances[index] = instance

def instance_class1:
    def __init__(self, functions_manager):
        functions_manager.register_instance(1, self)
    ...

This registration mechanism works best if FunctionsManager and instance_classX instances are meant to be created once and the live forever (or as long as the application runs).

1
  • Thank you. For now I think that your answer could help me to manage better the class FunctionsManager. May be in the future I'll find a structural change for my project which increases its quality. Commented Oct 22 at 9:37
1

It looks like you need a list, not an ever-expanding number of variables.

class FunctionsManager:
    def __init__(self, *instances):
        self.__instances = instances
    def handle_received_data(self, data):
        index = data[0] - 1
        return self.__instances[index].handle(data)
    def prepare_data(self):
        for instance in self.__instances:
            if instance.data_ready():
                return instance.get_data()

N.b. this doesn't change how FunctionsManager is created, it still takes positional arguments of however many instance types.

3
  • thank you. Remains the problem of the high number of instances for the __init__() method of FunctionsManager. What I'm looking for is a way to reduce this number of instances in the context in which I have to operate. For example a way to share the tasks execute by the FunctionsManager class. Commented Oct 22 at 8:27
  • 1
    @User051209 if you have a lot of instances, you have a lot of instances. That isn't necessarily a problem Commented Oct 22 at 8:34
  • Ok, may be I have to continue with this architecture. The suggestion of the list could be useful. Actually my real code is a bit more complex than I have described in the question but it is possible to pass to the use of one list of N instances instead N different attributes. Commented Oct 22 at 8:40

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.