python之pkgutil

pkgutil模块用于导入。

loader加载器

下面以一个服务函数get_loader()来解析查找模块加载器过程

def get_loader(module_or_name):
    """Get a PEP 302 "loader" object for module_or_name

    If the module or package is accessible via the normal import
    mechanism, a wrapper around the relevant part of that machinery
    is returned.  Returns None if the module cannot be found or imported.
    If the named module is not already imported, its containing package
    (if any) is imported, in order to establish the package __path__.

    This function uses iter_importers(), and is thus subject to the same
    limitations regarding platform-specific special import locations such
    as the Windows registry.
    """
    if module_or_name in sys.modules:
        module_or_name = sys.modules[module_or_name]
    if isinstance(module_or_name, ModuleType):
        module = module_or_name
        loader = getattr(module, '__loader__', None)
        if loader is not None:
            return loader
        fullname = module.__name__
    else:
        fullname = module_or_name
    return find_loader(fullname)
首先,检查模块名是否存在于sys.modules列表中,则获取该模块类型。

其次,检查入参模块类型是否属于模块类型,如果是,并且该模块有__loader__属性,则直接返回该属性的加载器

最后,调用find_loader()查找加载器

def find_loader(fullname):
    """Find a PEP 302 "loader" object for fullname

    If fullname contains dots, path must be the containing package's __path__.
    Returns None if the module cannot be found or imported. This function uses
    iter_importers(), and is thus subject to the same limitations regarding
    platform-specific special import locations such as the Windows registry.
    """
    for importer in iter_importers(fullname):
        loader = importer.find_module(fullname)
        if loader is not None:
            return loader

    return None

def iter_importers(fullname=""):
    if fullname.startswith('.'):
        raise ImportError("Relative module names not supported")
    if '.' in fullname:
        # Get the containing package's __path__
        pkg = '.'.join(fullname.split('.')[:-1])
        if pkg not in sys.modules:
            __import__(pkg)
        path = getattr(sys.modules[pkg], '__path__', None) or []
    else:
        for importer in sys.meta_path:
            yield importer
        path = sys.path
    for item in path:
        yield get_importer(item)
    if '.' not in fullname:
        yield ImpImporter()
fullname分为2种情况:

  • 带.分割的路径。先获取目录路径,如果该路径没有加载过,则先加载,然后从sys.modules种获取该路径的模块,如果该模块存在__path__,则获取__path__作为后面查找加载器的路径查找所有加载器
  • 不带.分割的路径。如果sys.meta_path中存在加载器,则返回加载器,返回里面所有加载器后,再以sys.path中所有路径查找所有加载器

def get_importer(path_item):
    """Retrieve a PEP 302 importer for the given path item

    The returned importer is cached in sys.path_importer_cache
    if it was newly created by a path hook.

    If there is no importer, a wrapper around the basic import
    machinery is returned. This wrapper is never inserted into
    the importer cache (None is inserted instead).

    The cache (or part of it) can be cleared manually if a
    rescan of sys.path_hooks is necessary.
    """
    try:
        importer = sys.path_importer_cache[path_item]
    except KeyError:
        for path_hook in sys.path_hooks:
            try:
                importer = path_hook(path_item)
                break
            except ImportError:
                pass
        else:
            importer = None
        sys.path_importer_cache.setdefault(path_item, importer)

    if importer is None:
        try:
            importer = ImpImporter(path_item)
        except ImportError:
            importer = None
    return importer

查找sys.path_importer_cache(sys.path_importer_cache类型是字典)。找不到就会抛异常,然后遍历sys.path_hooks中的对象并调用之,找到一个importer则不再遍历

如果前面找到的importer为空,则返回一个默认ImpImporter



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值