Search code examples
pythonpython-2.7getattr

python calling classes dynamically


I want to call python classes dynamically,

These are the classes that I want to call

class AutosoukModelMakeFuzzyComparisonModule:
    def __init__(self,configurationLoader=None, moduleConfigurationFile=None, settings=None):
        pass

and

class DefaultFuzzyComparisonModule:
    def __init__(self,configurationLoader, moduleConfigurationFile, settings = None):
        pass

and these too classes located in fuzzymodules folder

and I call them from ** FuzzyComparisonPipeline.py** which is in the same directory as fuzzymodules like this:

for module in FuzzyComparisonPipeline.fuzzyModules:
        name = module['name']
        configurationLoader = module['configurationLoader']
        moduleConfigurationFile = module['moduleConfigurationFile']
        settings = module['settings']
        module_to_import = __import__('fuzzymodules.'+name)
        instanceOfModule = getattr(module_to_import, name).__init__(configurationLoader, moduleConfigurationFile, settings)
        #instanceOfModule(configurationLoader, moduleConfigurationFile, settings)
    return item

I got this error:

   Traceback (most recent call last):
  File "path to my FuzzyComparisonPipeline.py", line 9, in process_item
    instanceOfModule = getattr(module_to_import, name).__init__(configurationLoader, moduleConfigurationFile, settings)
TypeError: module.__init__() takes at most 2 arguments (3 given)

and my question is how the init() takes 2 arguments, as you see, in both classes the init takes three arguments

Could you help please

i can't give you the whole code, because it is so complicated, everything else is working fine, i am sure of that, my problem is in calling that function.

the values of the for loop coming from this xml

<FuzzyComparison>
    <Modules>
        <Module>
            <name>AutosoukModelMakeFuzzyComparisonModule</name>
            <configurationLoader>DefaultLoader</configurationLoader>
            <configurationFile>MakesModels.conf</configurationFile>
            <settings></settings>
        </Module>
        <Module>
            <name>DefaultFuzzyComparisonModule</name>
            <configurationLoader>DefaultLoader</configurationLoader>
            <configurationFile>Buildings.conf</configurationFile>
            <settings>
                <attribute>building</attribute>
                <second>2222duxk fuck fuck</second>
            </settings>
        </Module>
    </Modules>
    </FuzzyComparison>

Solution

  • You are retrieving a module, not the class in the module; the __import__() function returns the top-level package, not the nested module itself.

    You really want to use importlib.import_module() instead here, it behaves as you expect.

    Next, you want to call the class object thus retrieved, not the __init__ method directly. Let Python call that for you, it'll do so to initialise the instance you create by calling the class:

    from importlib import import_module
    
    for module in FuzzyComparisonPipeline.fuzzyModules:
        name = module['name']
        configurationLoader = module['configurationLoader']
        moduleConfigurationFile = module['moduleConfigurationFile']
        settings = module['settings']
        module_to_import = import_module('fuzzymodules.' + name)
        instance = getattr(module_to_import, name)(configurationLoader, moduleConfigurationFile, settings)