在Python 3中创建“虚拟”模块的最佳方法

问题描述 投票:0回答:1

问题描述

我有一个包含与操作系统相关的模块的软件包。这些模块各自具有相同的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)

这似乎可行,但是似乎有些古怪。同样,必须保持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

一个警告是,模块规范将包含原始模块名称。 (这可能是错误或功能-我目前尚不完全了解其中的含义。)>

问题
  • 您对每种方法都有哪些缺点?

  • 是否有更好的方法或“最佳实践”?
  • 问题描述我有一个包含与操作系统相关的模块的软件包。这些模块各自具有相同的API。在客户端代码中,我可以执行以下操作:如果platform.system()==“ Windows”:...

    python python-3.x architecture python-module
    1个回答
    0
    投票

    [我认为我找到了一个被黑客入侵较少的解决方案,并且似乎在极端情况下更有效:

    © www.soinside.com 2019 - 2024. All rights reserved.