2

I am trying to write Python 2.7 code that will

  1. Dynamically load a list / array of modules from a config file at startup
  2. Call functions from those modules. Those functions are also designated in a config file (maybe the same config file, maybe a different one).

The idea is my code will have no idea until startup which modules to load. And the portion that calls the functions will have no idea which functions to call and which modules those functions belong to until runtime.

I'm not succeeding. A simple example of my situation is this:

The following is abc.py, a module that should be dynamically loaded (in my actual application I would have several such modules designated in a list / array in a config file):

    def abc_fcn():
        print("Hello World!")

    def another_fcn():
        print("BlahBlah")

The following is the .py code which should load abc.py (my actual code would need to import the entire list / array of modules from the config file). Both this .py file and abc.py are in the same folder / directory. Please note comments next to each statement.

    module_to_import = "abc"        #<- Will normally come from config file
    fcn_to_call = "abc.abc_fcn"     #<- Will normally come from config file

    __import__(module_to_import)    #<- No error

    print(help(module_to_import))   #<- Works as expected
    eval(fcn_to_call)()             #<- NameError: name 'abc' is not defined

When I change the second line to the following...

    fcn_to_call = "abc_fcn"

...the NameError changes to "name 'abc_fcn' is not defined".

What am I doing wrong? Thanks in advance for the help!

2 Answers 2

2

__import__ only returns the module specified, it does not add it to the global namespace. So to accomplish what you want, save the result as a variable, and then dynamically retrieve the function that you want. That could look like

fcn_to_call = 'abc_fcn'
mod = __import__(module_to_import)
func = getattr(mod, fcn_to_call)
func()

On a side note, abc is the name of name of the Abstract Base Classes builtin Python module, although I know you were probably just using this an example.

Sign up to request clarification or add additional context in comments.

5 Comments

You're right: this was just an example. I did think about using getattr as you suggest. The problem is my code would import several modules and call several functions not knowing which module owns which function. If fcn_to_call was "abc.abc_fcn" then my code would have to split on the '.' to get both the module name and the function name. I can definitely do that but it seemed like more work than necessary. When I use python interactively, I can type in "import abc" followed by "eval('abc.abc_fcn')()" and it works exactly as expected. What am I missing?
Because as I mentioned, the __import__ function - unlike the import keyword - does not put the module in question in the global namespace. If you want to do that, write abc = __import__('abc') followed by global abc.
Aah. Got it. Awesome! Thanks for the help!
So sorry, but I just realized this doesn't solve it for me. I realized my question wasn't complete and I edited it. The thing is at startup a LIST of modules would be imported, so using your suggestion "mod" would be a LIST; i.e. mod[0] would be one module, mod[1] would be another and so on. Later on the function would need to be called. Using your suggestion how would "func" know which element of the LIST mod to use? I guess mod could be a dictionary with the module name as the key. Is that the best way? Thanks again!
Mathew's and blhsing's suggestions got me most of the way. Here's what I needed in addition: (a) store the list of modules in the config file (b) have the application load those on startup (c) assign all of them to a Dict with keys being the module names (d) have the application split a function string (e.g. "abc.abc_fcn") on the "." to get a LIST (e) use the first element in the LIST as a key to look up the module in the Dict mentioned previously (f) call getattr(mod, LIST[1])(); LIST[1] (2nd element in the LIST) is the function (e.g. "fcn_abc"). I don't know a cleaner way as of now.
0

You should assign the returning value of __import__ to a variable abc so that you can actually use it as a module.

abc = __import__(module_to_import)

2 Comments

Thanks for the suggestion. I changed "__import__(module_to_import)" to the function you suggested, but the same error appeared. I tried making changes accordingly to the rest of my code but I wasn't sure what changes those would be. One thing I should have mentioned is the actual code will need to dynamically import a list / array of modules defined in the config file as opposed to just one. I'll edit the original post to state that.
OK, I understand now. Thanks for the help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.