简体   繁体   中英

Referencing a python file from a module when loaded by import_module

I want to import a module using import_module from importlib. When I do that the files I reference from my module are not found. If I import my module normally from the python shell (not using main.py) it works as expected. Also, if I add the path of MyModule.py to sys.path it works but from what I understand I'm not supposed to do that (commented out in the code below).

How can I get my referenced file to be loaded also when the module is loaded by import_module?

I have the following file structure

main.py
  subfolders
    folder1
      __init__.py
      MyModule.py
      hello.py

Contents of main.py

from importlib import import_module

modulename = 'subfolders.folder1.MyModule'
print("Import module ", modulename)
module = import_module(modulename)
m_instance = module.MyModule()

m_instance.module_hello()

Contents of MyModule.py

#This is the solution that works but feels wrong
#import os, sys
#sys.path.append(os.path.dirname(__file__))

from hello import hello_world

class MyModule(object):
    def __init__(self):
        print("Init MyModule")

    def module_hello(self):
        hello_world()

Contents of hello.py

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

When I run this I get:

c:\git\PythonImportTest>python main.py
Import module  subfolders.folder1.MyModule
Traceback (most recent call last):
  File "main.py", line 5, in <module>
    module = import_module(modulename)
  File "C:\Miniconda3\lib\importlib\__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 986, in _gcd_import
  File "<frozen importlib._bootstrap>", line 969, in _find_and_load
  File "<frozen importlib._bootstrap>", line 958, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 673, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 665, in exec_module
  File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed
  File "c:\git\PythonImportTest\subfolders\folder1\MyModule.py", line 5, in <module>
    from hello import hello_world
ImportError: No module named 'hello'

First you need to make your subfolders directory a package by placing an empty __init__.py in there. Second you need to import your hello module either by absolute import or relative import.

Absolute import:

from subfolders.folder1.hello import hello_world

Relative import:

from .hello import hello_world

The way you do it at the moment will look for hello.py in your top-level package (where your main.py is). As it can not be found there you get an error.

Note on relative imports in Python3

You propably switched from Python2 to Python3 which is why you get in trouble when using implicit relative imports. As PEP404 says:

In Python 3, implicit relative imports within packages are no longer available - only absolute imports and explicit relative imports are supported. In addition, star imports (eg from x import * ) are only permitted in module level code.

Meaning your code should work on Python2 but for Python3 you have to use one of the above options. See also: Changes in import statement python3

the problem with your code is that subfolders is a folder and not a package. if you are using import_module it is only possible to search in packages for subpackages.

Solution: Create a init .py in your subfolders folder and import folder1 there.

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