我正在通过继承__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上第一次运行正常。
答案 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']