延迟加载python子模块,importlib第一次失败

时间:2018-06-17 22:54:23

标签: python python-3.x

我正在通过继承__init__.py并定义每个子模块的属性来尝试在包ModuleType中延迟加载符号的想法。访问包名称空间中的符号将触发导入。我已经开始工作了,但出于某种原因,我对import_module的调用在第一次尝试时失败了,我不明白为什么。

我有一个很小的例子。假设这样的包:

my_package:
    __init__.py
    m1.py

这是__init__.py

import sys
import importlib
from types import ModuleType


class MyModule(ModuleType):
    @property
    def m1(self):
        try:
            _m1 = importlib.import_module('.m1', __package__)
        except AttributeError:
            print('second try ...')
            _m1 = importlib.import_module('.m1', __package__)

        return _m1


old = sys.modules[__name__]
new = MyModule(__name__)
new.__path__ = old.__path__

for k, v in list(old.__dict__.items()):
    new.__dict__[k] = v

sys.modules[__name__] = new

import_module来电始终失败并显示AttributeError: module 'my_package' has no attribute 'm1'。但是,第二次呼叫总是成功。换句话说,当我my_package.m1时,我总是得到m1,但它总是打印'second try ...'

注意,行为取决于python版本。对import_lib的调用在python2.7上第一次运行正常。

1 个答案:

答案 0 :(得分:1)

这是python2与python3之间的区别。

在python3中,importlib.import_module调用最终结束 here 这是对setattr的调用。由于您没有为.setter定义 您的财产,您将获得AttributeError

在python2中,importlib.import_module调用结束 here 这是对可能运行的内置__import__的调用 直接在模块__dict__上。

唯一的问题是它在python3中如何运作。一世 本以为会总是导致AttributeError

只要您创建.setter,您的代码就可以正常工作:

@m1.setter
def m1(self, mod):
    self.__dict__['m1'] = mod

实际上,.setter可以做任何事情, 包括pass,因为您无条件拨打 import_module

我会考虑使用上面的.setattr并将吸气剂更改为:

@property
def m1(self):
    if not self.__dict__.get('m1'):
        self.__dict__['m1'] = importlib.import_module('.m1', __package__)
    return self.__dict__['m1']