简体   繁体   中英

Python relative __import__

Suppose I have a module package containing the following files. An empty file C:\\codes\\package\\__init__.py and some non-trivial files:

One located in C:\\codes\\package\\first.py

def f():
    print 'a'

Another located in C:\\codes\\package\\second.py

def f():
    print 'b'

There is also a third file: C:\\codes\\package\\general.py with the following code

def myPrint(module_name):
    module = __import__(module_name)
    module.f()

if __name__ == '__main__':
    myPrint('first')
    myPrint('second')

When I run the latter file, everything goes fine. However, if I try to execute the file C:\\codes\\test.py containing

if __name__ == '__main__':
    from package import general
    general.myPrint('first')
    general.myPrint('second')

I get the import error ImportError: No module named first . How to resolve this issue?

First, I suspect you forgot to metion you have a (possibly empty) file package\\__init__.py which makes package a package. Otherwise, from package import general wouldn't work.

The second case differs from the first in so far as you are in a package. From inside a package, you wouldn't do import first , but import .first . The equivalent to the latter is described here where you either add level=1 as a parameter or (but I am not sure about that) you put .first into the string and set level to -1 (if it isn't the default nevertheless, that's not clear from the documentation).

Additionally, you have to provide at least globals() , so the right line is

module = __import__(module_name, globals(), level=1)

I have found this solution here .

In your case, you should import your module_name from package . Use fromlist argument:

getattr(__import__("package", fromlist=[module_name]), module_name)

Assuming, you're using Python 3, that's just because this version dropped the support for implicit relative imports . With Python 2 it would be working just fine.

So either you'd need to use relative imports in C:\\codes\\package\\general.py , which would result in erroneous call to it, or add your package to the path. A little dirty, but working hack would be:

def myPrint(module_name):
    pkg = os.path.dirname(__file__)
    sys.path.insert(0, pkg)
    try:
        module = __import__(module_name)
    except:
        raise
    finally:
        sys.path.remove(pkg)
    module.f()

Maybe you can achieve a cleaner implementation with the importlib module.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM