Create a python Class inheriting from a Class created by a function

75 views Asked by At

What works :

I am using the module recordtype to store global parameters for the different functions of my program.

Each parameter is a class instance of :

class Parameter(object):

    def __init__(self, name, value, info):
        self.name = name
        self.value = value
        self.info = info

Then the global structure is defined like this :

The individual parameters :

parameter_1 = Parameter('param_1', 10, 'Value for the parameter 1, usage...')
parameter_2 = Parameter('param_2', 20, 'Value for the parameter 2, usage...')
...
parameter_m = Parameter('param_n', 50, 'Value for the parameter m, usage...')
parameter_n = Parameter('param_n', 100, 'Value for the parameter n, usage...')

Parameter sub sets :

parameter_set_1 = recordtype('parameter_set_1', [(parameter_1.name, parameter_1), 
(parameter_2.name, parameter_2), ...])
...
parameter_set_n = recordtype('parameter_set_n', [(parameter_m.name, parameter_m), 
(parameter_n.name, parameter_n)]

The global parameter structure is then :

GlobalParametersFunction = recordtype('GlobalParameters', [('parameter_set_1', parameter_set_1()), 
('parameter_set_2', parameter_set_2()), ('parameter_set_n', parameter_set_n())])

Which needs to be instantiated :

GlobalParameters = GlobalParameterFunction()

This all works well, the GlobalParameterFunction creates a class where I can access individual parameters and change their values, Ex:

GlobalParameters.parameter_set_1.parameter_1.value = 20

From the GlobalParameters class instance I can then make a function that prints the values and their names :

def print_parameter_info(GP):
    for field, val in zip(GP._asdict(), GP._asdict().values()):
        print(field, ':')
        for key, entry in zip(val._asdict(), val._asdict().values()):
            print('\t', entry.name, ':', entry.value)

Which does a nice print for the user :

>>> print_parameter_info(GlobalParameters)

parameter_set_1 :
     parameter_1 : 10
     parameter_2 : 20
parameter_set_n :
     parameter_m : 50
     parameter_n : 100

I would also like to create a function such that :

change(GlobalParameters, 'name', new_value)

does :

GlobalParameters.parameter_set_1.name.value = new_value

Which seems easily doable with the class created by recordtype

The problem :

I would like to create a class methods for the GlobalParameters class instance, from the print_parameter_info() function such that :

GlobalParameters.print_parameter_info()

and

GlobalParameters.change(name, new_value)

works

because GlobalParameters is a class instance of recordtype, I tried :

class GlobalParameterClass(recordtype):
    
    def __init__(self):
        self = GlobalParameterFunction()

But because recordtype is a function creating a class ? I get the following error :

TypeError: function() argument 'code' must be code, not str

I found this question (2231427)

But after trying to import the right thing and looking at the source code of recordtype I think I understood that recordtype does not define a class clearly and creates it by parsing a string of code ?

Thus I do not understand how to create a class inheriting from the class created by recordtype

I also tried

class GlobalParameterClass(object):

    def __init__(self, *args):
        self = GlobalParameterFunction(*args)

This does not raise any errors but the class instance created is empty.

TLDR/Conclusion

How can I add custom methods to the class created by the recordtype function from the recordtype module ?

Or

Perhaps, there is there a better way to manage the GlobalParameters object ?

Thank you !

1

There are 1 answers

0
olivecha On

I found a solution without using the recordtype object, by creating a custom classes with the desired behavior :

class Parameter(object):
    """
    A class to store the individual sound parameters
    """
    def __init__(self, name, value, info):
        self.name = name
        self.value = value
        self.info = info

class ParameterSet(object):
    """
    A class to store multiple parameters as a set
    """
    def __init__(self, name, *parameters):
        self.name = name
        for parameter in parameters:
            setattr(self, parameter.name, parameter)

class GlobalParameters(object):
    """
    A class to store the parameter sets and to be used to assign parameter values to the different functions
    """
    def __init__(self, *parameter_sets):
        for parameter_set in parameter_sets:
            setattr(self, parameter_set.name, parameter_set)

The methods of the GlobalParameters classes go as follow :

    def info(self):
        for parameter_set in self.__dict__.values():
            print(parameter_set.name)
            parameters = [parameter for parameter in parameter_set_1.__dict__.values() if type(parameter) != str]
            for parameter in parameters:
                print('\t', parameter.name, ':', parameter.value)
                
    def change(self, name, value):
        for parameter_set in self.__dict__.values():
            parameters = [parameter for parameter in parameter_set_1.__dict__.values() if type(parameter) != str]
            for parameter  in parameters:
                if parameter.name == name:
                    parameter.value = value

With this example code :

# Individual parameters
parameter_1 = Parameter('parameter_1', 10, 'Value for the parameter 1, usage...')
parameter_2 = Parameter('parameter_2', 20, 'Value for the parameter 2, usage...')
parameter_n = Parameter('parameter_n', 50, 'Value for the parameter n, usage...')
parameter_m = Parameter('parameter_m', 100, 'Value for the parameter m, usage...')

# Parameter sets
parameter_set_1 = ParameterSet('parameter_set_1', parameter_1, parameter_2)
parameter_set_2 = ParameterSet('parameter_set_n', parameter_n, parameter_m)

# Global parameter set
GP = GlobalParameters(parameter_set_1, parameter_set_2)

I get the desired behavior :

>>> GP.info()
parameter_set_1
     parameter_1 : 10
     parameter_2 : 20
parameter_set_n
     parameter_1 : 10
     parameter_2 : 20

As well as with the .change method :

>>> GP.parameter_set_1.parameter_1.value
10

GP.change('parameter_1', 15)

>>> GP.parameter_set_1.parameter_1.value
15