【发布时间】:2020-07-29 20:26:47
【问题描述】:
问题描述
我有一个包含操作系统相关模块的包。这些模块每个都有相同的 API。
在客户端代码中,我可以执行以下操作:
import platform
if platform.system() == "Windows":
from my_package import os_win32 as my_package_platform
elif platform.system() == "Linux":
from my_package import os_linux as my_package_platform
# use my_package_platform in client code
但是我想做类似的事情
from my_package import my_package_platform
并让它自动导入正确的模块。
可能的解决方案 1:真实模块从特定模块导入所有内容
其实有一个模块my_package_platform.py:
import platform
import importlib as imp
import importlib.util as impu
import sys
exports = ["symbol1", "symbol2"]
def update_globals(mod, var_list):
for var in var_list:
globals()[var] = mod.__dict__.get(var)
if platform.system() == "Windows":
mod = imp.import_module(".os_win32", __package__)
elif platform.system() == "Linux":
mod = imp.import_module(".os_linux", __package__)
else:
raise NotImplementedError("not implemented for platform %s".format(platform.system()))
update_globals(mod, exports)
这似乎工作,但似乎有点hacky。还必须维护 exports 变量。
可能的解决方案 2:使用sys.meta_path 操作创建“虚拟模块”
在包的__init__.py中添加以下内容:
import platform
import importlib.abc
import importlib.util as impu
import sys
class _VirtualModuleFinder(importlib.abc.MetaPathFinder):
def find_spec(self, fullname: str, path, target=None):
if fullname == __package__ + ".my_package_platform":
if platform.system() == "win32":
return impu.find_spec(__package__ + ".os_win32")
elif platform.system() == "Linux":
return impu.find_spec(__package__ + ".os_linux")
else:
return None
sys.meta_path.append(_VirtualModuleFinder())
这很优雅,但它似乎有点矫枉过正。另一方面,附加的Finder 仅在通过其他方式找不到模块时才被调用。
需要注意的是,模块规范将包含原始模块名称。 (这可能是错误或功能 - 我目前不完全理解其中的含义)。
问题
- 您认为每种方法都有哪些缺点?
- 是否有更好的方法或“最佳实践”?
【问题讨论】:
标签: python python-3.x architecture python-module