imp– 访问 import internals

源代码: Lib / imp.py

自版本3.4以后不推荐使用: imp包正在等待弃用importlib.


这个模块提供了用于实现import语句的机制的接口。它定义了以下常量和函数:

imp.get_magic

返回用于识别字节编译的代码文件的魔术字符串值(.pyc文件)。(对于每个Python版本,此值可能不同。)

自版本3.4以后不推荐使用:使用importlib.util.MAGIC_NUMBER而不是

imp.get_suffixes
返回一个3元素元组的列表,每个元素描述一个特定类型的模块。每个三元组的形式为(suffix, mode, type),其中suffix是要附加到模块名称的字符串,以形成要搜索的文件名,mode是传递给内置的模式字符串-in open() function打开文件(对于文本文件可以是"r",对于二进制文件可以是"rb"),而type是文件类型,有其中一个值PY_SOURCE, PY_COMPILED,或C_EXTENSION,描述如下

自版本3.3以后删除:使用importlib.machinery上定义的常量代替

imp.find_module// (name [, path]
试着找到模块name。如果省略pathNone,则会搜索sys.path给出的目录名列表,但首先搜索几个特殊位置:该函数尝试查找内置模块使用thegiven名称(C_BUILTIN),然后是一个冻结的模块(PY_FROZEN),并且在某些系统上也会查看其他一些地方(在Windows上,它在注册表中看起来可能指向特定文件).

否则,path必须是目录名列表;每个目录都会搜索上面get_suffixes()返回的任何后缀的文件。列表中的无效名称被静默忽略(但所有列表项都必须是字符串).

如果搜索成功,返回值是一个3元素的元组(file,pathname, description)

file是一个开放的文件对象位于开头,pathname是找到的文件的路径名,descriptionget_suffixes()描述发现的那种模块.

如果模块没有存放在文件中,则返回fileNone,pathname是空字符串,description元组包含后缀和模式的emptystrings;模块类型表示为上面给出的内容。如果搜索不成功,ImportErrorisraised。其他例外表明问题orenvironment.

如果模块是一个包,fileNone, pathname是包路径和description中的最后一项元组是PKG_DIRECTORY.

此函数不处理分层模块名称(包含点的名称)。为了找到P.M,即包M的子模块P,使用find_module()load_module()查找并加载P然后使用find_module()并将path参数设置为P.__path__。当P本身有一个虚线名称时,递归应用此配方.

自版本3.3以后不推荐使用:使用importlib.util.find_spec()相反,除非需要Python 3.3兼容性,在这种情况下使用importlib.find_loader()。例如使用前一种情况,请参阅例子的一部分importlibdocumentation.

imp.load_modulename, file, pathname, description
加载之前由find_module()(或通过另一种进行的搜索产生兼容的结果)。此功能不仅仅是导入模块:如果模块已经导入,它将重新加载模块!nameargument表示fullmodule名称(包括包名称,如果这是apackage的子模块)。file参数是一个打开的文件,pathname是相应的文件名;这些可以是None"",分别是模块是包还是没有从文件加载。description参数是一个元组,由get_suffixes()返回,描述了必须加载的模块类型.

如果加载成功,则返回值为模块对象;否则,例外(通常是ImportError)被抬起来

重要:调用者负责关闭file参数,如果不是None,即使引发异常也是如此。最好用tryfinally陈述

自版本3.3以后删除:如果以前和imp.find_module()一起使用那么考虑使用importlib.import_module(),否则请使用您为imp.find_module()选择的替换装置。如果你直接用文件路径参数调用imp.load_module()和相关函数,那么使用importlib.util.spec_from_file_location()importlib.util.module_from_spec()的组合。有关各种方法的详细信息,请参阅文件示例importlib文件.

imp.new_module (name
返回一个名为name的新空模块对象。这个对象是not插入sys.modules.

自版本3.4以后不推荐使用使用importlib.util.module_from_spec()代替

imp.reloadmodule
重新装入以前进口的module。参数必须是模块对象,之前必须已成功导入。如果您使用外部编辑器编写模块源文件并希望在不离开Python解释器的情况下尝试新版本,这将非常有用。返回值是模块对象(与module参数相同).

执行reload(module)时:

  • 重新编译Python模块的代码并且重新执行模块级代码,定义一组新的对象,这些对象绑定到模块的字典中的名称。扩展模块的init功能不被称为secondtime.
  • 与Python中的所有其他对象一样,只有在引用计数降到零之后才会回收旧对象.
  • 模块命名空间中的名称被更新为指向任何new或changedobjects.
  • 其他对旧对象的引用(例如模块外部的名称)不会被反弹以引用新对象,并且必须在每个对象中更新如果需要,它们会出现在命名空间.

还有其他一些注意事项:

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

try:
    cache
except NameError:
    cache = {}

这是合法的虽然通常对重新加载内置或动态加载的模块没有多大用处,但sys, __main__builtins除外。但是,在很多情况下,扩展模块的设计不是多次初始化,可能会失败重新加载时以任意方式

如果模块使用fromimport …从另一个模块导入对象,则调用reload()对于另一个模块没有重新定义从它导入的对象 – 一种方法是重新执行from语句,另一种方法是使用import和qualifiednames(module.*name *)而不是

如果一个模块实例化一个类的实例,重新加载定义该类的模块不会影响实例的方法定义 – 它们继续使用旧的类定义。对于派生类也是如此.

在版本3.3中更改:依赖于__name____loader__在模块重新加载时定义而不是仅仅__name__.

自版本3.4以后不推荐使用:使用importlib.reload()代替

以下功能便于处理 PEP 3147 byte-compiledfile paths.

新版本3.2.

imp.cache_from_source (path, debug_override=None)
返回 PEP 3147 与源path关联的字节编译文件的路径。例如,如果path/foo/bar/baz.py,对于Python 3.2,返回值将是/foo/bar/__pycache__/baz.cpython-32.pyccpython-32字符串来自当前的魔术标签(见get_tag();如果sys.implementation.cache_tag没有定义然后NotImplementedError将被提出)。通过TrueFalse传入debug_override你可以覆盖__debug__的系统值,导致优化的字节码.

path不需要存在。

改版3.3:如果sys.implementation.cache_tagNone, 然后NotImplementedError被养了

从版本3.4开始不推荐使用:使用 importlib.util.cache_from_source()代替。

在版本3.5中更改:debug_override参数不再创建.pyo文件。

imp.source_from_cachepath
鉴于 pathPEP 3147 文件名,返回关联的源代码文件路径。例如,如果path/foo/bar/__pycache__/baz.cpython-32.pyc返回的路径是/foo/bar/baz.py. path不存在,但如果不符合PEP 3147 格式,ValueError被提出来了。如果sys.implementation.cache_tag没有定义,NotImplementedError被养了

改版3.3:举起NotImplementedError什么时候sys.implementation.cache_tag没有定义。

从版本3.4开始不推荐使用:使用 importlib.util.source_from_cache()代替。

imp.get_tag
退回PEP 3147 魔法标记字符串匹配此版本的Python’smagic数字,由get_magic().

返回自版本3.4以后不推荐使用:使用sys.implementation.cache_tag直接从Python 3.3.

开始以下函数有助于与导入系统的内部锁定机制进行交互。锁定语义的导入是一个实现细节,可能因发行版本而异。但是,Python确保循环导入工作没有任何死锁.

imp.lock_held ()
如果全局导入锁当前被保持,则返回True,否则False。在没有线程的平台上,总是返回False.

在具有线程的平台上,执行导入的线程首先持有全局导入锁,然后为导入的其余部分设置每模块锁。这会阻止其他线程导入相同的模块,直到原始导入完成,从而阻止其他线程看到原始线程构造的不完整的模块对象。对于循环导入有一个例外,通过构造必须在某些时候暴露出一个不完整的模块对象.

在版本3.3中更改:锁定方案已经改为大多数部分的模块锁。对于某些关键任务保留全局导入锁定,例如初始化每个模块的锁定.

自版本3.4以后重新编写.

imp.acquire_lock (
获取当前线程的解释器全局导入锁。导入挂钩应使用此锁,以确保在导入模块时的线程安全性.

一旦线程获得了导入锁定,同一个线程就可以在不阻塞的情况下获取它;线程必须在每次获取它时才释放一次.

在没有线程的平台上,这个功能什么都不做.

在版本3.3中更改:锁定方案有在大多数情况下改为按模块锁定。对于某些关键任务保留全局导入锁定,例如初始化每个模块的锁定.

自版本3.4以后重新编写.

imp.release_lock (
释放解释器的全局导入锁定。在没有线程的平台上,这个函数什么都不做.

在版本3.3中更改:锁定方案已经改为大多数部分的每个模块锁。对于某些关键任务保留全局导入锁定,例如初始化每个模块的锁定.

自版本3.4以后重新编写.

以下本模块中定义的具有整数值的常量是用于表示find_module().

imp.PY_SOURCE
的搜索结果该模块被发现为源文件.

自版本3.3以后已弃用.

imp.PY_COMPILED
该模块被发现是一个编译的代码对象文件.

自版本3.3以后已弃用.

imp.C_EXTENSION
该模块被发现是可动态加载的共享库.

自版本3.3以后已弃用.

imp.PKG_DIRECTORY
该模块被发现为软件包目录.

自版本3.3以后更改.

imp.C_BUILTIN
该模块被发现为内置模块.

自版本3.3以后弃用

imp.PY_FROZEN
该模块被发现是一个冷冻模块.

自版本3.3以后改为.

class imp.NullImporter (path_string
NullImporter类型是一个 PEP 302 导入钩子,由于未能找到任何模块而处理非目录路径字符串。使用现有目录或空字符串调用此类型会引发ImportError。否则,将返回NullImporter实例.

实例只有一种方法:

find_modulefullname[, path]
这个方法总是返回None,表示找不到所要求的模块.

改版3.3:None被插入sys.path_importer_cache而不是NullImporter.

从版本3.4开始不推荐使用:插入 Nonesys.path_importer_cache代替。

 

例子

以下函数模拟了到1.4的标准导入语句(没有分层模块名称)。(这implementation在那个版本中不起作用,因为find_module()已经延长了load_module()已添加1.4。)

import imp
import sys

def __import__(name, globals=None, locals=None, fromlist=None):
    # Fast path: see if the module has already been imported.
    try:
        return sys.modules[name]
    except KeyError:
        pass

    # If any of the following calls raises an exception,
    # there's a problem we can't handle -- let the caller handle it.

    fp, pathname, description = imp.find_module(name)

    try:
        return imp.load_module(name, fp, pathname, description)
    finally:
        # Since we may exit via an exception, close fp explicitly.
        if fp:
            fp.close()