【问题标题】:ModuleNotFoundError using "classic" import on module imported from importlibModuleNotFoundError 在从 importlib 导入的模块上使用“经典”导入
【发布时间】:2019-08-23 10:55:39
【问题描述】:

TL,DR

我已经:

mod = import_module('path.module')

在那之后,我想要/需要做什么:

from mod.script import func

但这给了我:

ModuleNotFoundError: No module named 'mod.script'

警告:使用“mod.script.func()”或类似的方式调用它不能满足我的需要(项目约束),我搜索如何使用类似“from”的语法[module_imported_from_importlib] 导入 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

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

目标

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

旧 script1.py :

from script2 import <func>

新脚本1.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/init.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()

能够运行我的测试功能

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

【问题讨论】:

    标签: python import module python-importlib


    【解决方案1】:

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

    如果你想使用自定义名称的自定义模块,最好的办法是创建一个模块并给他你想要的名称: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')
    

    使用它,我可以保留所有导入,仅在“管理器”文件中指定版本,例如:

    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
    

    block1 => block1/v1
    块2 => 块2/v1

    但是这就是神奇的把戏
    在 block1/v2/script1.py 中:

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

    块1 => 块1/v2
    块 2 => 块 2/v2

    版本不同,但代码完全相同

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

    问候,

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-16
      • 1970-01-01
      • 2021-12-03
      • 1970-01-01
      • 2018-11-25
      • 2018-11-27
      • 2019-10-30
      相关资源
      最近更新 更多