sys.modules的作用与用法详解

发布时间:2023-05-20

sys.modules是一个Python解释器的内置模块,它是一个字典,维护了系统中所有已经导入模块的引用。

一、sys.modules 锁定

在Python中,所有模块的导入操作都会加载对应的py文件转换为一个“模块对象”,并将其存储在sys.modules中。我们可以通过sys.modules中的字典查找特定模块,但在多线程环境中,如果两个或多个线程尝试同时导入同一个模块,会有一个线程拿到锁来解决竞争冲突。此时会出现“模块锁定”的问题。

import sys
import threading
import time
def worker():
    print('Worker thread started')
    time.sleep(1)
    module_name = 'math'
    if module_name not in sys.modules:
        # 模拟模块导入
        __import__(module_name)
        print(f'{module_name} has successfully imported')
threads = [threading.Thread(target=worker) for _ in range(5)]
_ = [t.start() for t in threads]

执行代码段,会导致所有线程中有其中一个线程要进行模块导入,结束惊喜输出显示math模块只导入了一次,而其他的线程被隔离复用了这个已经导入好的math模块。这就是因为在主线程和Worker线程都要导入math模块,由于sys.modules本身是一个字典对象,因此负责导入模块线程对sys.modules字典的修改可能会被另一个线程图谋会取回。

二、sys.modules[name]

如果在模块文件中通过命令行直接运行文件,那么Python会将全局变量__name__的值设置为__main__。如果使用import语句导入这个模块时,那么__name__的值就是导入模块文件名,而不是__main__。在导入模块时,我们可以使用sys.modules[__name__]来访问该模块本身。

# module1.py
import sys
def print_module_name():
    print(sys.modules[__name__].__name__)
# main.py
import module1
module1.print_module_name()

执行代码段,输出结果为:

module1

三、sys.modules的作用

sys.modules的主要作用是帮助引用已经被导入的Python模块,避免重复操作。Python机制会在模块被导入之后将其缓存到sys.modules字典中,并在下一次对其进行访问时立即返回模块的引用,从而加速程序的运行效率。在使用时可以直接用模块名或者sys.modules[module_name]来读取缓存中的模块对象,甚至可以从这里直接删除一个模块的缓存,通过重新导入来更新模块的内容。

四、sys.modules值删除

Python会在程序进程启动时自动导入大量模块,大多数情况下,我们并不需要这些模块。如果你想清除缓存的sys.modules字典中的所有引用,可以在程序中删除它,如下所示:

# Clearing all previously imported modules
sys.modules.clear()

五、sys.modules的用法

1. sys.modules.keys()

sys.modules的keys()方法可以返回一个包含所有模块名的list,即已经被加载到Python解释器内存中的所有模块,如:

print(sys.modules.keys())

输出结果为:

dict_keys(['builtins', '__main__', '_frozen_importlib', '_imp', '_thread', '_warnings', '_weakref', 'sys', '_io', 'marshal', 'posix', 'zipimport', 'encodings', '_codecs', 'codecs', '_sre', 'sre_compile', '_pickle', 'pickle', 'weakref', 'atexit', 'errno', 'fcntl', '_stat', '_collections', 'abc', 'io', 'opcode', 'operator', 'signal', '_signal', 'posixpath', '_posixpath', 'genericpath', 'os', '_sitebuiltins', 'site'])

2. sys.modules tornado

比如我们安装了tornado模块,我们可以使用sys.modules['tornado']来访问tornado包中的内容,如下所示:

import sys
sys.modules['tornado'].__version__

输出结果如下:

'6.1'

3. sys.modules switch

我们可以在Python开发过程中手动切换当前环境中模块版本。例如,让我们假设你有两个版本的requests库,我们想手动切换版本。可以使用sys.module导入返回的模块对象,从而启用不同的版本:

import sys
import requests
sys.modules['requests'] = __import__('requests_new_version', globals(), locals(), ['*'])

注意其中的'new_version'字样需要替换成你想要导入的版本字符。

六、sys.modules什么意思

sys.modules实际上是一个存储当前 Python 解释用到的所有模块的字典。Python通常只会在第一次导入时将这些模块存储在sys.modules中,以后就可以直接从字典缓存中获取模块对象。 sys.modules是一个十分重要的模块且内置于Python环境,对于熟练使用Python的开发人员而言,它可以帮助我们编写高效的、更加Pythonic的代码,提升编码速度和代码质量。