Search code examples
pythonobjectimport

Can't dynamically import using "from x import y"


I am writing a function to check if the importing file/module contains any error. The function for some reasons failed when I use the module name as a variable.

Works


def importfile1():
    try:
        from test2 import bea
        print('1st scenario:', 'import is successful')
    except:
        print('1st scenario:', 'import failed')
        
importfile1()

Does not work

def importfile2(bank):
    try:
        from test2 import bank
        print('2nd scenario:', 'import is successful')
    except:
        print('2nd scenario:', 'import failed')
        
importfile2(bea)

I expected both functions to work. However, the second function failed.

The results are shown below:

1st scenario: import is successful
2nd scenario: import failed

May I know why the second function failed?


Solution

  • Some vocabulary to start off. When you import something in Python, you're not importing a file. You're importing a module, which is a collection of other Python objects (classes, functions, variables, etc.). So when you write from time import sleep, you're making the interpreter import the time module and look inside it for an object (in this case, a function) called sleep.

    In your case, it seems like you're passing a string to bank so you can import the bank object from the test2 module. That has two main problems:

    1. You can't pass a variable into an import statement. The interpreter is expecting a module or object. It's not expecting a variable, even if that variable contains the name of a module or object. In other words, the interpreter won't look in the test2 module for the name inside bank; it'll look for an object that's literally called test2.bank.

    2. Even if you could do that, the interpreter doesn't understand strings. For example, from time import "sleep" wouldn't do anything because "sleep" is a string; you'd have to omit the quotes for it to work. This is basically what your code is trying to do; if you called test2("function"), you'd be trying to write from test2 import "function" instead of from test2 import function.

    As @metatoaster commented, the usual solution for these kinds of imports would be the importlib package. However, importlib is really only meant for loading entire modules; your question makes it seem like you're trying to get the bank object from the test2 module.

    If that's the case, you could try importing the test2 module just like you did in the importfile1 function (no problems there since test2 is neither a variable nor a string) and using the getattr method to get the specific object from that module. getattr takes strings and (like all Python functions) understands variable arguments, so you can use bank to access the object you're looking for with no issues. Something like this might help:

    def importfile2(bank):
        try:
            import test2
            imported = getattr(test2, bank)
            newObject = imported("Bob", 26) # Example usage if bank is a class/function
            newValue = imported + 5 # Example usage if bank is a variable/constant
            
            print('2nd scenario:', 'import is successful')
        except:
            print('2nd scenario:', 'import failed')
    

    This'll only work while you're still in the importfile2 function; if you're planning on using the imported object outside of that, you'll need to learn about namespaces.

    Also, I'm inclined to wonder why you want these imports in a function. It might be worth reading this question to determine whether it's really necessary.