python / 3.7.2rc1 / all / library-importlib.html

importlib —导入的实现

3.1 版中的新Function。

源代码: Lib/importlib/init.py


Introduction

importlib软件包的目的是双重的。一种是在 Python 源代码中提供import语句的实现(因此,pass扩展来表示import()函数)。这提供了import的实现,该实现可移植到任何 Python 解释器中。这也提供了比用 Python 以外的其他编程语言实现的实现更容易理解的实现。

第二,此包中公开了实现import的组件,从而使用户更容易创建自己的自定义对象(通常称为importer)以参与导入过程。

See also

Functions

  • importlib. __import__(* name globals = None locals = None fromlist =() level = 0 *)

Note

以编程方式导入模块应使用import_module()代替此Function。

  • importlib. import_module(* name package = None *)
    • 导入模块。 * name 参数指定以绝对或相对术语(例如pkg.mod..mod)导入的模块。如果使用相对术语指定名称,则必须将 package *参数设置为要用作解析软件包名称的锚点的软件包名称(例如import_module('..mod', 'pkg.subpkg')将导入pkg.mod)。

import_module()函数充当importlib.import()的简化包装。这意味着该函数的所有语义都源自importlib.import()。这两个函数之间最重要的区别是import_module()返回指定的程序包或模块(例如pkg.mod),而import()返回顶级程序包或模块(例如pkg)。

如果您要动态导入自解释程序开始执行以来创建的模块(例如,创建了 Python 源文件),则可能需要调用invalidate_caches(),以便导入模块注意到新模块。

在版本 3.3 中更改:父程序包将自动导入。

  • importlib. find_loader(* name path = None *)
    • 查找模块的加载器,可以选择在指定的* path *内。如果模块在sys.modules中,则返回sys.modules[name].__loader__(除非加载器将为None或未设置,在这种情况下会引发ValueError)。否则,将使用sys.meta_path进行搜索。如果找不到加载程序,则返回None

点名没有隐式导入其父项,因为这需要加载它们并且可能不希望这样做。要正确导入子模块,您将需要导入子模块的所有父包,并使用正确的参数* path *。

版本 3.3 中的新Function。

在版本 3.4 中进行了更改:如果未设置__loader__,请提高ValueError,就像将属性设置为None一样。

从 3.4 版开始不推荐使用:改为使用importlib.util.find_spec()

  • importlib. invalidate_caches ( )
    • 使存储在sys.meta_path的查找器的内部缓存无效。如果发现者实现invalidate_caches(),那么它将被调用以执行无效操作。如果在程序运行时创建/安装了任何模块,则应调用此函数,以确保所有查找者都将注意到新模块的存在。

版本 3.3 中的新Function。

  • importlib. reload(* module *)
    • 重新加载先前导入的* module *。参数必须是模块对象,因此它必须已经成功导入。如果您已使用外部编辑器编辑了模块源文件,并且想在不离开 Python 解释器的情况下try新版本,则这将非常有用。返回值是模块对象(如果重新导入导致将不同的对象放置在sys.modules中,则可以不同)。

当执行reload()时:

  • 重新编译 Python 模块的代码并重新执行模块级代码,从而定义了一组新对象,这些对象pass重用最初加载模块的loader绑定到模块字典中的名称。扩展模块的initFunction不再被调用。

  • 与 Python 中的所有其他对象一样,旧对象仅在其引用计数降至零后才被回收。

  • 模块名称空间中的名称将更新为指向任何新的或更改的对象。

  • 对旧对象的其他引用(例如模块外部的名称)不会反弹以引用新对象,并且如果需要的话,必须在出现它们的每个命名空间中进行更新。

还有其他一些警告:

重新加载模块时,将保留其字典(包含模块的全局变量)。名称的重新定义将覆盖旧的定义,因此这通常不是问题。如果模块的新版本未定义旧版本定义的名称,则保留旧定义。如果此Function维护模块的全局表或对象缓存,则可以利用该模块的优势-使用try语句,它可以测试表的存在并在需要时跳过其初始化:

try:
    cache
except NameError:
    cache = {}

通常,重新加载内置或动态加载的模块不是很有用。不建议重新加载sysmainbuiltins和其他关键模块。在许多情况下,扩展模块不会被初始化一次以上,并且在重新加载时可能会以任意方式失败。

如果一个模块使用fromimport…从另一个模块导入对象,则对另一个模块调用reload()不会重新定义从该模块导入的对象-一种解决方法是重新执行from语句,另一种方法是使用import和限定名称(* module.name *)代替。

如果模块实例化一个类的实例,则重新加载定义该类的模块不会影响实例的方法定义-它们将 continue 使用旧的类定义。派生类也是如此。

3.4 版的新Function。

在版本 3.7 中进行了更改:当要重装的模块缺少ModuleSpec时,引发ModuleNotFoundError

importlib.abc –与导入相关的抽象 Base Class

源代码: Lib/importlib/abc.py


importlib.abc模块包含import使用的所有核心抽象 Base Class。还提供了一些核心抽象 Base Class 的子类,以帮助实现核心 ABC。

ABC hierarchy:

object
 +-- Finder (deprecated)
 |    +-- MetaPathFinder
 |    +-- PathEntryFinder
 +-- Loader
      +-- ResourceLoader --------+
      +-- InspectLoader          |
           +-- ExecutionLoader --+
                                 +-- FileLoader
                                 +-- SourceLoader
  • 类别 importlib.abc. Finder
    • 表示finder的抽象 Base Class。

自版本 3.3 起不推荐使用:改为使用MetaPathFinderPathEntryFinder

  • 抽象方法 find_module(全名路径=无)
    • 查找指定模块的loader的抽象方法。最初在 PEP 302中指定,此方法旨在用于sys.meta_path和基于路径的导入子系统。

在版本 3.4 中进行了更改:调用时返回None而不是引发NotImplementedError

  • 类别 importlib.abc. MetaPathFinder

版本 3.3 中的新Function。

  • find_spec((全名路径目标=无)
    • 查找指定模块的spec的抽象方法。如果这是顶级导入,则* path 将为None。否则,这是在搜索子包或模块,并且 path *将是父包中path的值。如果找不到规范,则返回None。传入时,target是一个模块对象,查找程序可以使用它来对返回的规格进行更有根据的猜测。 importlib.util.spec_from_loader()对于实现具体的MetaPathFinders可能有用。

3.4 版的新Function。

  • find_module(全名路径)
    • 查找指定模块的loader的旧方法。如果这是顶级导入,则* path 将为None。否则,这是在搜索子包或模块,并且 path *将是父包中path的值。如果找不到加载程序,则返回None

如果定义了find_spec(),则提供向后兼容Function。

在版本 3.4 中进行了更改:调用时返回None而不是引发NotImplementedError。可以使用find_spec()提供Function。

从 3.4 版开始不推荐使用:改为使用find_spec()

在版本 3.4 中进行了更改:调用时返回None而不是NotImplemented

  • 类别 importlib.abc. PathEntryFinder
    • 表示路径查找器的抽象 Base Class。尽管PathEntryFinderMetaPathFinder有一些相似之处,但它只能在PathFinder提供的基于路径的导入子系统中使用。仅出于兼容性原因,此 ABC 是Finder的子类。

版本 3.3 中的新Function。

  • find_spec((全名,* target = None *)
    • 查找指定模块的spec的抽象方法。查找器仅在分配了该模块的path entry内搜索模块。如果找不到规范,则返回None。传入时,target是一个模块对象,发现者可以使用它来对返回的规格进行更有根据的猜测。 importlib.util.spec_from_loader()对于实现具体的PathEntryFinders可能有用。

3.4 版的新Function。

  • find_loader(全名)
    • 查找指定模块的loader的旧方法。返回(loader, portion)的 2Tuples,其中portion是构成名称空间包一部分的文件系统位置的序列。装入程序可以是None,同时指定portion以表示文件系统位置对名称空间包的贡献。 portion可以使用一个空列表来表示加载程序不属于名称空间包。如果loaderNoneportion是空列表,则找不到命名空间包的加载程序或位置(即找不到模块的任何内容)。

如果定义了find_spec(),则将提供向后兼容Function。

在版本 3.4 中进行了更改:返回(None, [])而不是NotImplementedError。在提供Function时使用find_spec()

从 3.4 版开始不推荐使用:改为使用find_spec()

从 3.4 版开始不推荐使用:改为使用find_spec()

  • invalidate_caches ( )

    • 可选方法,该方法在调用时应使查找程序使用的任何内部缓存无效。当使所有缓存的查找器的缓存无效时,由PathFinder.invalidate_caches()使用。
  • 类别 importlib.abc. Loader

    • loader的抽象 Base Class。有关加载程序的确切定义,请参见 PEP 302

希望支持资源读取的加载程序应实现importlib.abc.ResourceReader指定的get_resource_reader(fullname)方法。

在 3.7 版中进行了更改:引入了可选的get_resource_reader()方法。

  • create_module(* spec *)
    • 一种返回模块对象以在导入模块时使用的方法。此方法可能返回None,指示默认模块创建语义应该发生。

3.4 版的新Function。

在版本 3.5 中进行了更改:从 Python 3.6 开始,定义exec_module()时该方法将不是可选的。

  • exec_module(* module *)
    • 导入或重新加载模块时,将在其自己的名称空间中执行模块的抽象方法。调用exec_module()时,该模块应已初始化。存在此方法时,必须定义create_module()

3.4 版的新Function。

在 3.6 版中进行了更改:还必须定义create_module()

  • load_module(全名)
    • 加载模块的旧方法。如果无法加载模块,则引发ImportError,否则返回已加载的模块。

如果所请求的模块已存在于sys.modules中,则应使用该模块并重新加载该模块。否则,加载程序应创建一个新模块,并在开始任何加载之前将其插入sys.modules,以防止从导入中递归。如果加载程序插入了一个模块,但加载失败,则必须由加载程序从sys.modules卸下;在加载程序开始执行之前,sys.modules中已经存在的模块应单独放置(请参见importlib.util.module_for_loader())。

加载程序应在模块上设置几个属性。 (请注意,重新加载模块时,其中某些属性可能会更改):

    • name

      • 模块的名称。
    • file

      • 存储模块数据的路径(未为内置模块设置)。
    • cached

      • 应该/应该存储模块的编译版本的路径(如果该属性不合适,则不设置)。
    • path

      • 字符串列表,用于指定包中的搜索路径。未在模块上设置此属性。

exec_module()可用时,将提供向后兼容Function。

在版本 3.4 中更改:调用时提高ImportError而不是NotImplementedErrorexec_module()可用时提供的Function。

从 3.4 版开始不推荐使用:推荐的用于加载模块的 API 为exec_module()(和create_module())。加载程序应实现它而不是 load_module()。当执行 exec_module()时,导入机制将负责 load_module()的所有其他职责。

  • module_repr(* module *)
    • 一种传统方法,在实现时会以字符串形式计算并返回给定模块的 repr。模块类型的默认 repr()将适当地使用此方法的结果。

版本 3.3 中的新Function。

在版本 3.4 中进行了更改:使其成为可选方法,而不是抽象方法。

从版本 3.4 开始不推荐使用:导入机制现在自动执行此操作。

  • 类别 importlib.abc. ResourceReader

从该 ABC 的角度来看,* resource *是包装中附带的二进制工件。通常,这就像是数据文件,位于包装的__init__.py文件旁边。此类的目的是帮助抽象出对此类数据文件的访问,以使包及其数据文件是否存储在文件中都无关紧要。 zip 文件与文件系统上的文件。

对于此类的任何方法,* resource 参数应为path-like object,从概念上讲它仅表示文件名。这意味着 resource *参数中不应包含子目录路径。这是因为阅读器所针对的软件包的位置充当“目录”。因此,目录和文件名的隐喻分别是包和资源。这也是为什么希望此类的实例直接与特定程序包相关(而不是潜在地表示多个程序包或模块)的原因。

希望支持资源读取的加载程序应该提供一种名为get_resource_reader(fullname)的方法,该方法返回实现此 ABC 接口的对象。如果全名指定的模块不是软件包,则此方法应返回None。仅当指定的模块是软件包时,才应返回与此 ABC 兼容的对象。

3.7 版中的新Function。

  • 抽象方法 open_resource(资源)
    • 返回一个打开的file-like object,用于* resource *的二进制读取。

如果找不到资源,则引发FileNotFoundError

  • 抽象方法 resource_path(资源)
    • 返回* resource *的文件系统路径。

如果文件系统上不存在该资源,请引发FileNotFoundError

  • 抽象方法 is_resource(名称)

    • 如果命名的* name 被视为资源,则返回True。如果 name *不存在,则引发FileNotFoundError
  • 抽象方法 contents()

    • 返回包内容中的iterable个字符串。请注意,不需要迭代器返回的所有名称都是实际资源,例如可以返回is_resource()为 Pseudo 名称。

允许返回非资源名称是为了允许先验地知道包及其资源的存储方式,并且非资源名称将很有用。例如,允许返回子目录名称,以便当已知包和资源存储在文件系统上时,可以直接使用那些子目录名称。

abstract 方法返回无项目的可迭代对象。

  • 类别 importlib.abc. ResourceLoader
    • loader的抽象 Base Class,它实现了可选的 PEP 302协议,用于从存储后端加载任意资源。

从 3.7 版开始不推荐使用:不推荐使用此 ABC,以支持passimportlib.abc.ResourceReader加载资源。

  • 抽象方法 get_data(路径)
    • 返回位于* path 的数据的字节的抽象方法。具有允许存储任意数据的类似文件的存储后端的加载程序可以实现此抽象方法,以直接访问存储的数据。如果找不到 path *,将引发OSError。 * path *预计将使用模块的file属性或包的path的项构造。

在版本 3.4 中更改:提高OSError而不是NotImplementedError

  • 类别 importlib.abc. InspectLoader

    • loader的抽象 Base Class,该类为检查模块的加载程序实现了可选的 PEP 302协议。
  • get_code(全名)

    • 返回模块的代码对象,或者返回None(如果该模块没有代码对象)(例如,内置模块的情况)。如果加载程序找不到请求的模块,请引发ImportError

Note

尽管该方法具有默认实现,但建议为性能起见将其覆盖。

在版本 3.4 中进行了更改:不再是抽象的,并且提供了具体的实现。

  • 抽象方法 get_source(全名)
    • 返回模块源的抽象方法。它使用universal newlines作为文本字符串返回,将所有可识别的行分隔符转换为'\n'个字符。如果没有可用的来源(例如内置模块),则返回None。如果加载程序找不到指定的模块,则引发ImportError

在版本 3.4 中更改:提高ImportError而不是NotImplementedError

  • is_package(全名)
    • 如果模块是包,则返回真值的抽象方法,否则返回假值。如果loader找不到模块,则引发ImportError

在版本 3.4 中更改:提高ImportError而不是NotImplementedError

  • 静态 source_to_code(数据路径='')
    • 从 Python 源创建代码对象。
  • data *参数可以是compile()函数支持的值(即字符串或字节)。 * path *参数应该是源代码所源自的“路径”,它可以是抽象概念(例如 zip 文件中的位置)。

使用后续代码对象,可以pass运行exec(code, module.__dict__)在模块中执行它。

3.4 版的新Function。

在版本 3.5 中更改:使方法静态。

3.4 版的新Function。

自 3.4 版起已弃用:改为使用exec_module()

  • 类别 importlib.abc. ExecutionLoader

    • InspectLoader继承的抽象 Base Class,该 Base Class 在实现时有助于将模块作为脚本执行。 ABC 代表可选的 PEP 302协议。
  • 抽象方法 get_filename(全名)

    • 一种抽象方法,该方法返回指定模块的file值。如果没有可用路径,则引发ImportError

如果源代码可用,则该方法应返回源文件的路径,而不管是否使用字节码加载模块。

在版本 3.4 中更改:提高ImportError而不是NotImplementedError

  • fullname *参数是加载程序要处理的模块的完全解析名称。 * path *参数是模块文件的路径。

版本 3.3 中的新Function。

  • name

    • 加载程序可以处理的模块的名称。
  • path

    • 模块文件的路径。
  • load_module(全名)

    • 呼叫 super 的load_module()

从 3.4 版开始不推荐使用:改为使用Loader.exec_module()

此类定义的抽象方法是添加可选的字节码文件支持。不实现这些可选方法(或导致它们引发NotImplementedError)将导致加载程序仅使用源代码。实现这些方法使加载程序可以处理源字节码文件;它不允许仅提供字节码的“无源”加载。字节码文件是一种优化方法,它pass删除 Python 编译器的解析步骤来加快加载速度,因此没有公开特定于字节码的 API。

  • path_stats(* path *)

    • 可选的抽象方法,该方法返回包含有关指定路径的元数据的dict。支持的字典键是:
  • 'mtime'(必填):表示源代码修改时间的整数或浮点数;

  • 'size'(可选):源代码的大小(以字节为单位)。

字典中的任何其他键都将被忽略,以允许将来扩展。如果无法处理该路径,则引发OSError

版本 3.3 中的新Function。

在版本 3.4 中更改:提高OSError而不是NotImplementedError

  • path_mtime(* path *)
    • 可选的抽象方法,它返回指定路径的修改时间。

从版本 3.3 开始不推荐使用:不推荐使用此方法,而推荐使用path_stats()。您不必实现它,但出于兼容性目的,它仍然可用。如果无法处理路径,请抬高OSError

在版本 3.4 中更改:提高OSError而不是NotImplementedError

  • set_data(* path data *)
    • 可选的抽象方法,它将指定的字节写入文件路径。任何不存在的中间目录将自动创建。

当由于路径是只读(errno.EACCES/PermissionError)而导致写入路径失败时,请勿传播该异常。

在版本 3.4 中进行了更改:调用时不再提高NotImplementedError

3.4 版的新Function。

从 3.4 版开始不推荐使用:改为使用exec_module()

importlib.resources –资源

源代码: Lib/importlib/resources.py


3.7 版中的新Function。

该模块利用 Python 的 import 系统提供对* packages 中的 resources *的访问。如果可以导入软件包,则可以访问该软件包中的资源。可以以二进制或文本模式打开或读取资源。

资源大致类似于目录中的文件,但请记住,这只是一个隐喻,这一点很重要。资源和包 不必 作为文件系统上的物理文件和目录存在。

Note

该模块提供的Function类似于pkg_resources 基本资源访问,而没有该程序包的性能开销。这使阅读包中包含的资源变得更加容易,并且语义更加稳定和一致。

此模块的独立 backport 提供有关using importlib.resources从 pkg_resources 迁移到 importlib.resources的更多信息。

希望支持资源读取的加载程序应实现importlib.abc.ResourceReader指定的get_resource_reader(fullname)方法。

定义了以下类型。

  • importlib.resources. Package

    • Package类型定义为Union[str, ModuleType]。这意味着在函数描述接受Package的地方,您可以传入字符串或模块。模块对象必须具有可解析的__spec__.submodule_search_locations而不是None
  • importlib.resources. Resource

    • 此类型描述传递给此程序包中各个函数的资源名称。定义为Union[str, os.PathLike]

以下Function可用。

  • importlib.resources. open_binary(* package resource *)
    • 打开以二进制方式读取* package 中的 resource *。
  • package *是符合Package要求的名称或模块对象。 * resource 是要在 package *中打开的资源的名称;它可能不包含路径分隔符,并且可能没有子资源(即它不能是目录)。该函数返回一个typing.BinaryIO实例,一个二进制 I/O 流已打开以供读取。
  • importlib.resources. open_text(* package resource encoding ='utf-8' errors ='strict'*)
    • 打开以阅读* package 中的 resource *的文本。默认情况下,该资源被打开以作为 UTF-8 读取。
  • package *是符合Package要求的名称或模块对象。 * resource 是要在 package *中打开的资源的名称;它可能不包含路径分隔符,并且可能没有子资源(即它不能是目录)。 * encoding errors 具有与内置open()相同的含义。

此函数返回一个typing.TextIO实例,一个文本 I/O 流已打开以供读取。

  • importlib.resources. read_binary(* package resource *)
    • bytes读取并返回* package 中的 resource *的内容。
  • package *是符合Package要求的名称或模块对象。 * resource 是要在 package *中打开的资源的名称;它可能不包含路径分隔符,并且可能没有子资源(即它不能是目录)。此函数以bytes的形式返回资源的内容。
  • importlib.resources. read_text(* package resource encoding ='utf-8' errors ='strict'*)
    • str的形式读取并返回* package 中的 resource *的内容。默认情况下,内容被读取为严格的 UTF-8.
  • package *是符合Package要求的名称或模块对象。 * resource 是要在 package *中打开的资源的名称;它可能不包含路径分隔符,并且可能没有子资源(即它不能是目录)。 * encoding errors 具有与内置open()相同的含义。此函数以str的形式返回资源的内容。
  • importlib.resources. path(* package resource *)
    • 将路径返回到* resource *作为实际的文件系统路径。此函数返回一个上下文 Management 器以用于with语句。上下文 Management 器提供了一个pathlib.Path对象。

退出上下文 Management 器会清除需要从中提取资源时创建的任何临时文件。一个 zip 文件。

  • package *是符合Package要求的名称或模块对象。 * resource 是要在 package *中打开的资源的名称;它可能不包含路径分隔符,并且可能没有子资源(即它不能是目录)。
  • importlib.resources. is_resource(* package name *)

    • 如果程序包中有一个名为* name *的资源,则返回True,否则返回False。请记住,目录不是“ *”资源! * package *是符合Package要求的名称或模块对象。
  • importlib.resources. contents(* package *)

    • 返回包装中命名项的可迭代项。迭代器返回str个资源(例如文件)和非资源(例如目录)。该可迭代对象不会递归到子目录中。
  • package *是符合Package要求的名称或模块对象。

importlib.machinery –导入程序和路径钩子

源代码: Lib/importlib/machinery.py


该模块包含帮助import查找和加载模块的各种对象。

  • importlib.machinery. SOURCE_SUFFIXES
    • 代表源模块识别的文件后缀的字符串列表。

版本 3.3 中的新Function。

  • importlib.machinery. DEBUG_BYTECODE_SUFFIXES
    • 代表未优化字节码模块的文件后缀的字符串列表。

版本 3.3 中的新Function。

从版本 3.5 开始不推荐使用:改为使用BYTECODE_SUFFIXES

  • importlib.machinery. OPTIMIZED_BYTECODE_SUFFIXES
    • 代表优化后的字节码模块的文件后缀的字符串列表。

版本 3.3 中的新Function。

从版本 3.5 开始不推荐使用:改为使用BYTECODE_SUFFIXES

  • importlib.machinery. BYTECODE_SUFFIXES
    • 代表字节码模块(包括前导点)的已识别文件后缀的字符串列表。

版本 3.3 中的新Function。

在版本 3.5 中进行了更改:该值不再取决于__debug__

  • importlib.machinery. EXTENSION_SUFFIXES
    • 代表扩展模块识别的文件后缀的字符串列表。

版本 3.3 中的新Function。

  • importlib.machinery. all_suffixes ( )
    • 返回表示标准导入机制识别的模块的所有文件后缀的字符串组合列表。这是代码的帮助者,它仅需要知道文件系统路径是否潜在地引用了模块,而无需任何有关模块类型的详细信息(例如inspect.getmodulename())。

版本 3.3 中的新Function。

此类仅定义类方法以减轻实例化的需求。

在版本 3.5 中进行了更改:作为 PEP 489的一部分,内置导入器现在实现Loader.create_module()Loader.exec_module()

此类仅定义类方法以减轻实例化的需求。

在版本 3.4 中更改:获得了create_module()exec_module()方法。

此类仅定义类方法以减轻实例化的需求。

版本 3.3 中的新Function。

自版本 3.6 起不推荐使用:而是使用site配置。默认情况下,Future 版本的 Python 可能不会启用此查找程序。

此类仅定义类方法以减轻实例化的需求。

  • 类方法 find_spec(全名路径=无目标=无)

3.4 版的新Function。

在版本 3.5 中进行了更改:如果当前工作目录(由空字符串表示)不再有效,则返回None,但没有值被缓存在sys.path_importer_cache中。

  • 类方法 find_module(全名路径=无)

从 3.4 版开始不推荐使用:改为使用find_spec()

在 3.7 版中进行了更改:删除了sys.path_importer_cache中的None条目。

在版本 3.4 中进行了更改:在sys.path_hooks中使用当前工作目录''调用对象(即空字符串)。

    • class * importlib.machinery. FileFinder(* path * loader_details *)
  • path *参数是查找器负责搜索的目录。

  • loader_details *参数是可变数量的 2 项 Tuples,每个 Tuples 包含一个加载程序以及该加载程序可以识别的文件后缀序列。加载程序应该是可调用的,可以接受模块名称和找到的文件路径的两个参数。

查找器将根据需要缓存目录内容,对每个模块进行统计调用以验证缓存是否过时。由于缓存的陈旧性取决于文件系统的 os 状态信息的粒度,因此存在潜在的竞争条件,即搜索模块,创建新文件,然后搜索新文件代表的模块。如果操作发生得足够快以适合 stat 调用的粒度,则模块搜索将失败。为防止这种情况发生,在动态创建模块时,请确保调用importlib.invalidate_caches()

版本 3.3 中的新Function。

  • path

    • 查找器将搜索的路径。
  • find_spec((全名,* target = None *)

    • try在path中找到处理全名的规范。

3.4 版的新Function。

  • find_loader(全名)

    • try找到要在path内处理* fullname *的加载程序。
  • invalidate_caches ( )

    • 清除内部缓存。
  • 类方法 path_hook(** loader_details *)

    • 返回用于sys.path_hooks的闭包的类方法。闭包使用直接给闭包指定的路径参数返回FileFinder的实例,并间接使用* loader_details *返回。

如果闭包的参数不是现有目录,则引发ImportError

版本 3.3 中的新Function。

自版本 3.6 起不推荐使用:改为使用importlib.abc.Loader.exec_module()

  • 类别 importlib.machinery. SourcelessFileLoader(全名路径)

请注意,直接使用字节码文件(因此不是源代码文件)会禁止您的模块在所有更改字节码格式的 Python 实现或新版本的 Python 中使用。

版本 3.3 中的新Function。

  • name

    • 加载程序将处理的模块的名称。
  • path

    • 字节码文件的路径。
  • is_package(全名)

    • 确定模块是否为基于path的程序包。
  • get_code(全名)

    • 返回从path创建的name的代码对象。
  • get_source(全名)

    • 返回None,因为使用此加载程序时字节码文件没有源。
  • load_module(* name = None *)

importlib.abc.Loader.load_module()的具体实现是可选的,其中指定要加载的模块的名称。

自版本 3.6 起不推荐使用:改为使用importlib.abc.Loader.exec_module()

  • fullname *参数指定加载程序要支持的模块的名称。 * path *参数是扩展模块文件的路径。

版本 3.3 中的新Function。

  • name

    • 加载程序支持的模块的名称。
  • path

    • 扩展模块的路径。
  • create_module(* spec *)

    • 根据 PEP 489从给定的规范创建模块对象。

3.5 版中的新Function。

  • exec_module(* module *)
    • 根据 PEP 489初始化给定的模块对象。

3.5 版中的新Function。

  • is_package(全名)

    • 如果文件路径指向基于EXTENSION_SUFFIXES的程序包的__init__模块,则返回True
  • get_code(全名)

    • 由于扩展模块缺少代码对象,因此返回None
  • get_source(全名)

    • 返回None,因为扩展模块没有源代码。
  • get_filename(全名)

3.4 版的新Function。

    • class * importlib.machinery. ModuleSpec(* name loader **,* origin = None loader_state = None is_package = None *)
    • 模块与导入系统有关的状态的规范。通常将其公开为模块的__spec__属性。在下面的描述中,括号中的名称给出了直接在模块对象上可用的相应属性。例如。 module.__spec__.origin == module.__file__。但是请注意,虽然* values *通常是等效的,但是由于两个对象之间没有同步,因此它们可能会有所不同。因此,可以在运行时更新模块的__path__,而这不会自动反映在__spec__.submodule_search_locations中。

3.4 版的新Function。

  • name

( __name__ )

一个字符串,表示模块的标准名称。

  • loader

( __loader__ )

用于加载的加载器。对于名称空间包,应将其设置为None

  • origin

( __file__ )

加载模块的位置的名称,例如“内置”用于内置模块,文件名用于从源加载的模块。通常应设置“ origin”,但它可以是None(默认值),表示未指定(例如,用于名称空间包)。

  • submodule_search_locations

( __path__ )

字符串列表,用于在哪里找到子模块(如果为软件包,则为None)。

  • loader_state

容器,用于在加载过程中使用额外的模块特定数据(或None)。

  • cached

( __cached__ )

编译模块应存储的字符串(或None)。

  • parent

( __package__ )

(只读)模块作为子模块所属的软件包的全限定名称(或None)。

  • has_location

布尔值,指示模块的“来源”属性是否引用可加载位置。

importlib.util –import 商的 Util 代码

源代码: Lib/importlib/util.py


此模块包含有助于构建importer的各种对象。

  • importlib.util. MAGIC_NUMBER
    • 代表字节码版本号的字节。如果您需要有关加载/写入字节码的帮助,请考虑importlib.abc.SourceLoader

3.4 版的新Function。

  • importlib.util. cache_from_source(* path debug_override = None **,* optimization = None *)
    • PEP 3147/ PEP 488路径返回到与源* path 关联的字节编译文件。例如,如果 path *为/foo/bar/baz.py,则对于 Python 3.2,返回值将为/foo/bar/__pycache__/baz.cpython-32.pyccpython-32字符串来自当前的魔术标记(请参见get_tag();如果未定义sys.implementation.cache_tag则将引发NotImplementedError)。
  • optimization *参数用于指定字节码文件的优化级别。空字符串表示没有优化,因此/foo/bar/baz.py的_optimization ''会导致/foo/bar/__pycache__/baz.cpython-32.pyc的字节码路径。 None导致使用解释器的优化级别。使用任何其他值的字符串表示形式,因此/foo/bar/baz.py(优化)为2会导致字节码路径为/foo/bar/__pycache__/baz.cpython-32.opt-2.pyc。 * optimization *的字符串表示形式只能是字母数字,否则将引发ValueError

  • debug_override 参数已被弃用,可用于覆盖__debug__的系统值。 True值等效于将 optimization 设置为空字符串。 False的值与将 optimization 设置为1的值相同。如果两个 debug_override optimization *都不都是None,则引发TypeError

3.4 版的新Function。

在版本 3.5 中进行了更改:添加了* optimization 参数,并且不建议使用 debug_override *参数。

在版本 3.6 中更改:接受path-like object

  • importlib.util. source_from_cache(* path *)
    • 给定 PEP 3147文件名的* path ,返回相关的源代码文件路径。例如,如果 path *是/foo/bar/__pycache__/baz.cpython-32.pyc,则返回的路径将是/foo/bar/baz.py。 * path *不必存在,但是,如果它不符合 PEP 3147 PEP 488格式,则会引发ValueError。如果未定义sys.implementation.cache_tag,则引发NotImplementedError

3.4 版的新Function。

在版本 3.6 中更改:接受path-like object

3.4 版的新Function。

  • importlib.util. resolve_name(* name package *)
    • 将相对模块名称解析为绝对名称。

如果“名称”没有前导点,则仅返回“名称”。这允许使用诸如importlib.util.resolve_name('sys', __package__)之类的用法,而无需检查是否需要 package 参数。

如果 name 是相对模块名称,但 package 是错误的值(例如None或空字符串),则引发ValueError。还提出了ValueError的相对名称,该相对名称会逸出其包含的数据包(例如,从spam数据包中请求..bacon)。

版本 3.3 中的新Function。

  • importlib.util. find_spec(* name package = None *)
    • 查找模块的spec,可以相对于指定的“包”名称进行查找。如果模块位于sys.modules,则返回sys.modules[name].__spec__(除非规范为None或未设置,在这种情况下ValueError升高)。否则,将使用sys.meta_path进行搜索。如果找不到规格,则返回None

如果 name 用于子模块(包含点),则会自动导入父模块。

namepackage 的工作方式与import_module()相同。

3.4 版的新Function。

在 3.7 版中进行了更改:如果 package 实际上不是包(即缺少path属性),则提起ModuleNotFoundError而不是AttributeError

如果spec.loader.create_module不返回None,则不会重置任何先前存在的属性。另外,如果在访问 spec 或在模块上设置属性时触发,则不会引发AttributeError

此Function优于使用types.ModuleType创建新模块,因为 spec 用于在模块上设置尽可能多的导入控制属性。

3.5 版中的新Function。

  • @ importlib.util. module_for_loader
    • decorator用于importlib.abc.Loader.load_module()处理选择要加载的适当模块对象。装饰的方法应该具有一个带有两个位置参数(例如load_module(self, module))的调用签名,第二个参数将是加载器要使用的模块 object 。请注意,由于有两个参数,装饰器将无法在静态方法上使用。

装饰的方法将采用loader的预期加载模块的名称。如果在sys.modules中找不到该模块,则将构建一个新模块。无论模块来自何处,loader都设置为 self ,并且package是根据importlib.abc.InspectLoader.is_package()返回的值设置的(如果可用)。这些属性是无条件设置的,以支持重新加载。

如果修饰的方法引发异常,并且已将模块添加到sys.modules,则将删除该模块以防止部分初始化的模块留在sys.modules中。如果模块已经在sys.modules中,则将其单独放置。

在版本 3.3 中更改:尽可能自动设置loaderpackage

在版本 3.4 中进行了更改:无条件设置nameloader package以支持重新加载。

从版本 3.4 开始不推荐使用:导入机制现在直接执行此Function提供的所有Function。

在版本 3.4 中进行了更改:如果设置为None,则设置__loader__,就好像该属性不存在一样。

从版本 3.4 开始不推荐使用:导入机制将自动处理此问题。

从版本 3.4 开始不推荐使用:导入机制将自动处理此问题。

  • importlib.util. spec_from_loader(* name loader **,* origin = None is_package = None *)
    • 用于基于加载程序创建ModuleSpec实例的工厂函数。参数的含义与 ModuleSpec 的含义相同。该函数使用可用的loader API(例如InspectLoader.is_package())来填充规范上缺少的任何信息。

3.4 版的新Function。

  • importlib.util. spec_from_file_location(* name location **,* loader = None submodule_search_locations = None *)
    • 一种工厂Function,用于基于文件的路径创建ModuleSpec实例。缺少的信息将pass使用加载程序 API 以及模块将基于文件的含义填充在规范中。

3.4 版的新Function。

在版本 3.6 中更改:接受path-like object

  • importlib.util. source_hash(* source_bytes *)
    • 返回* source_bytes *的哈希值作为字节。基于散列的.pyc文件将相应源文件内容的source_hash()嵌入其标题中。

3.7 版中的新Function。

    • class * importlib.util. LazyLoader(* loader *)
    • 一个类,该类推迟模块的加载程序的执行,直到该模块访问了属性。

此类“仅**”与定义exec_module()的装载程序一起使用,以控制所需的模块类型。出于同样的原因,加载器的create_module()方法必须返回None或可以更改其__class__属性的类型,而不使用slots。最后,替换无法放置到sys.modules中的对象的模块将无法正常工作,因为无法安全地在整个解释器中正确替换模块引用;如果检测到这样的替换,则引发ValueError

Note

对于启动时间很关键的项目,如果从未使用过,则此类可潜在地最大程度地减少加载模块的成本。对于启动时间不是必需的项目,由于在加载过程中创建的错误消息被推迟从而在上下文之外发生,因此不建议大量使用此类。

3.5 版中的新Function。

在版本 3.6 中更改:开始调用create_module(),删除了importlib.machinery.BuiltinImporterimportlib.machinery.ExtensionFileLoader的兼容性警告。

  • 类方法 factory(加载器)
    • 返回创建惰性加载程序的可调用方法的静态方法。这旨在用于pass类而不是实例传递加载程序的情况。
suffixes = importlib.machinery.SOURCE_SUFFIXES
loader = importlib.machinery.SourceFileLoader
lazy_loader = importlib.util.LazyLoader.factory(loader)
finder = importlib.machinery.FileFinder(path, (lazy_loader, suffixes))

Examples

Importing programmatically

要以编程方式导入模块,请使用importlib.import_module()

import importlib

itertools = importlib.import_module('itertools')

检查是否可以导入模块

如果需要确定是否可以在不实际执行导入的情况下导入模块,则应使用importlib.util.find_spec()

import importlib.util
import sys

# For illustrative purposes.
name = 'itertools'

if name in sys.modules:
    print(f"{name!r} already in sys.modules")
elif (spec := importlib.util.find_spec(name)) is not None:
    # If you chose to perform the actual import ...
    module = importlib.util.module_from_spec(spec)
    sys.modules[name] = module
    spec.loader.exec_module(module)
    print(f"{name!r} has been imported")
else:
    print(f"can't find the {name!r} module")

直接导入源文件

要直接导入 Python 源文件,请使用以下配方(仅限 Python 3.5 和更高版本):

import importlib.util
import sys

# For illustrative purposes.
import tokenize
file_path = tokenize.__file__
module_name = tokenize.__name__

spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
sys.modules[module_name] = module
spec.loader.exec_module(module)

设置 import 商

对于导入的深度自定义,您通常需要实现importer。这意味着要同时 Management 事物的finderloader。对于查找者,根据您的需求有两种选择:元路径查找器路径查找器。前者是您要放在sys.meta_path上的内容,而后者是您使用sys.path_hooks上的路径进入钩子创建的内容,后者与sys.path条目一起使用,有可能创建查找程序。此示例将向您展示如何注册自己的导入器,以便导入将使用它们(要为自己创建导入器,请阅读此包中定义的适当类的文档):

import importlib.machinery
import sys

# For illustrative purposes only.
SpamMetaPathFinder = importlib.machinery.PathFinder
SpamPathEntryFinder = importlib.machinery.FileFinder
loader_details = (importlib.machinery.SourceFileLoader,
                  importlib.machinery.SOURCE_SUFFIXES)

# Setting up a meta path finder.
# Make sure to put the finder in the proper location in the list in terms of
# priority.
sys.meta_path.append(SpamMetaPathFinder)

# Setting up a path entry finder.
# Make sure to put the path hook in the proper location in the list in terms
# of priority.
sys.path_hooks.append(SpamPathEntryFinder.path_hook(loader_details))

Approximating importlib.import_module()

导入本身是用 Python 代码实现的,因此可以pass importlib 公开大多数导入机制。以下内容pass提供importlib.import_module()的大概实现来帮助说明 importlib 公开的各种 API(Python 3.4 及更高版本用于 importlib 使用,Python 3.6 及更高版本用于代码的其他部分)。

import importlib.util
import sys

def import_module(name, package=None):
    """An approximate implementation of import."""
    absolute_name = importlib.util.resolve_name(name, package)
    try:
        return sys.modules[absolute_name]
    except KeyError:
        pass

    path = None
    if '.' in absolute_name:
        parent_name, _, child_name = absolute_name.rpartition('.')
        parent_module = import_module(parent_name)
        path = parent_module.__spec__.submodule_search_locations
    for finder in sys.meta_path:
        spec = finder.find_spec(absolute_name, path)
        if spec is not None:
            break
    else:
        msg = f'No module named {absolute_name!r}'
        raise ModuleNotFoundError(msg, name=absolute_name)
    module = importlib.util.module_from_spec(spec)
    sys.modules[absolute_name] = module
    spec.loader.exec_module(module)
    if path is not None:
        setattr(parent_module, child_name, module)
    return module