ModuleNotFoundError 在从 importlib 导入的模块上使用 "classic" import

ModuleNotFoundError using "classic" import on module imported from importlib

TL,DR

我已经:

mod = import_module('path.module')

在那之后,我want/need要做的事情:

from mod.script import func

但这给了我:

ModuleNotFoundError: No module named 'mod.script'

Warning :使用 "mod.script.func()" 或类似的东西调用它不符合我的需要(项目约束),我搜索如何使用像 "from [module_imported_from_importlib] import XXX"

简介:

我需要将现有代码拆分到具有多个版本的不同文件夹中。目标是在应用程序中拥有不同的部分,每个部分都使用其他部分的指定版本。

示例树:

ref.py 
block1 
__init__.py
- v1
| __init__.py
|- __init__.py
|- script1.py
 block2
 __init__.py
- v1
| __init__.py
|-- __init__.py
|-- script2.py
- v2
|- __init__.py
|-- __init__.py
|-- script2.py

有了这个,我需要 运行 : /block2/v1/script2.py 函数在 /block1/v1/script1.py

目标

我尝试做的是使用相同的语法指定 script1 应该在哪里使用 "script2"(在 block2 中的 v1 或 v2 中),但只是指定没有版本的块(那会改变):

旧 script1.py :

from script2 import <func>

新script1.py

from block2.script2 import <func>

代码

我已经尝试了很多事情都没有成功,现在我在这里似乎接近解决方案但我找不到它(也许这是不可能的?):

在block1/v1/init.py :

from importlib import import_module, reload

MODULE = import_module('block2.v1') # With 'block2.v1' defined as a variable somewhere else (eg in ref.py)
reload(MODULE)

在block1/v1/script1.py中:

from block1.v1 import MODULE as block2
print(block2)
print(f'block2 : {dir(block2)}')
from block2.script2 import test

在block2/v1/初始化.py :

from block2.v1 import script2

print(script2)

在block2/v1/script2.py中:

def test():
    print("hello")

结果 # python block1/v1/script1.py :

<module 'block2.v1.script2' from 'xxx/block2/v1/script2.py'>
<module 'block2.v1.script2' from 'xxx/block2/v1/script2.py'>
<module 'block2.v1' from 'xxx/block1/v1/__init__.py'>
block2 : ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'script2']
Traceback (most recent call last):
  File "block1/v1/script1.py", line 17, in <module>
    from block2.script2 import test
ModuleNotFoundError: No module named 'block2.script2'

预期结果

很快,我希望在脚本 1 中有这个调用语法:

from block2.script2 import test
test()

能够运行我的测试功能

非常感谢帮助,我不知道它是否真的很清楚!

经过大量测试,我终于找到了一个不错的东西。

如果你想使用自定义名称的自定义模块,最好的办法是创建一个模块并给他你想要的名称:D

树:

/GLOBALCONFIG
|- /module_manager
  |- block1.py
  |- block2.py
  |- blocX..
- module_version_manager
/block1
|- /v1
   |- script1.py
|- /v2
   |- script1.py
/block2
|- /v1
   |- script2.py
|- /v2
   |- script2.py

为此,我在项目根目录下创建了一个名为 "GLOBALCONFIG" 的目录,其中包含一个 .py 管理器:

from importlib import import_module
import sys
import os

block1 = sys.modules['block1'] = import_module('block1.v1')
block2 = sys.modules['block2'] = import_module('block2.v1')

使用它,我可以保留所有导入,仅在 "manager" 文件中指定版本,例如:

block1/v1/script1.py :

from GLOBALCONFIG.module_manager.block1 import block2
from block2 import script2

如果我将 script2 放入 block2/v2 或 /v3 或任何,我只需要更改正确的版本以用于 block1.py 管理器中的 block2 并且代码仍然有效

另外,如果你想:
block1/v1 使用 block2/v1
block1/v2 使用 block2/v2

您可以创建一个引用全局配置中的模块/版本的字典:

module_version_manager.py :

block1_modules_versions = {
    'block1.v1': {
        'block2':'block2.v1',
    }
    'block1.v2': {
        'block2':'block2.v2',
    }
}

block2_modules_versions = {
    'block2.v2': {
        'block1':'block1.v1',
    }
   'block2.v2': {
        'block1':'block1.v2',
    }
}

然后,在您的 block1.py 经理中:

from GLOBALCONFIG.module_version_manager import block1_modules_versions
from importlib import import_module
import sys
import os

block1 = sys.modules['u1'] = import_module('.'.join(str.rsplit(sys.argv[0], "/")[3:5])) # give me the current version of the current block : block1.vX
block2 = sys.modules['block2'] = import_module(block1_modules_versions['.'.join(str.rsplit(sys.argv[0], "/")[3:5])]['block2']) # give me the block2 to use for the right block1.vX

在block1/v1/script1.py 中:

import sys
sys.argv[0] = __file__ # [path]/block1/v1/script1 => current path of executed script giving the right folder and import the right modules
from GLOBALCONFIG.module_manager.block1 import block1, block2

块 1 => block1/v1
block2 => block2/v1

但是这是一个神奇的技巧 :
在 block1/v2/script1.py 中:

import sys
sys.argv[0] = __file__
from GLOBALCONFIG.module_manager.block1 import block1, block2

块 1 => block1/v2
block2 => block2/v2

版本不同但代码完全相同

仅供参考:强制当前文件路径的 sys.argv[0] = file 对我来说是强制性的,因为我的服务开始使用 gunicon wsgi:app在 [venv]/bin/gunicorn 处设置了默认路径,但没有此约束,GLOBALCONFIG 导入应该可以很好地工作

此致,