python import module and reload

本文详细解析Python中模块的加载过程,包括搜索、编译和执行步骤,以及.pyc文件的作用。同时介绍了如何使用reload函数实现模块的重载,以便在代码修改后更新模块状态。

#模块的加载

不管是用import还是用from mmmm import *的方式导入模块,当程序运行之后,回头在看那个存储着mmmm.py文件的目录中,多了一个文件:

qw@qw-Latitude-E4300:~/Documents/ITArticles/BasicPython/codes$ ls mmm*
mmmm.py  mmmm.pyc

在这个目录下面,除了原来的那个mmmm.py之外,又多了一个mmmm.pyc文件,这个文件不是我写的,是哪里来的呢?

要破开此迷,需要用import的过程说起。

##import的工作流程

import mmmm,并不是仅仅将mmmm.py这个文件装载到当前位置(文件内),其实是首先进行了一次运算。当mmmm.py被第一次导入的时候,python首先要对其进行编译,生成扩展名为.pyc的同名文件,然后才执行mmmm模块的代码,创建相应的对象等。就如同把大象装进冰箱,有三步要执行:

  1. 搜索。就是python要能够找到import的模块。怎么找到,后面讲述。
  2. 编译。找到模块文件之后,将其编译成字节码,就是那个.pyc文件里面的(关于字节码,下面会介绍,请继续阅读)。注意,不是什么时候都编译的,只有第一次运行时候才编译,如果mmmm.py文件改变了,相当于又一个新文件,也会从新编译。其实就是.pyc文件中有一个时间戳,python会自动检查这个时间戳,如果它比同名的.py文件时间戳旧,就会从新编译。否则跳过。当然,如果根本就没有找到同名的.py源文件,只有字节码文件.pyc,那么就只能运行这个了。
  3. 运行。这就没什么好说的了,生米已经淘干净了,并且放到锅里,开始加热了,最后就只能熟饭了。执行就是前面已经编译的模块字节码文件,顺理成章要执行了。

##搜索模块

一般情况下,python会自动的完成模块搜索过程。但是,在某些情况下,或许会要求程序员来设定搜索路径。当import一个模块后,python会按照下面的顺序来找那个将要导入的模块文件

  1. 程序的主目录。上一讲中,在codes这个目录中运行交互模式,这时候的主目录就是codes,当在那个交互模式中运行import mmmm的时候,就首先在codes这个目录中搜索相应的文件(找到.py之后编译成为.pyc)。当然,后面在网页编程中,看官会看到,所谓主目录是可以通过顶层文件设置的目录。
  2. PYTHONPATH目录。这是一个环境变量设置,如果没有设置则滤去。如何进行环境变量设置,请看官google啦。
  3. 标准库目录。已经随着Python的安装进入到计算机中的那个。
  4. 任何.pth文件的内容。如果有这类文件,最后要在这类文件中搜索一下。这是一个简单的方法,在.pth文件中,加入有效目录,使之成为搜索路径。下图就是我的计算机上,存放.pth文件的位置以及里面放着的.pth文件

看官也可以自己编写.pth文件,里面是有关搜索目录,保存到这里。比如,打开目录中的easy-install.pth文件,发现的内容:

搜索就是这么一个过程。这里建议看官了解即可,不一定非要进行什么设置,在很多情况下,python都是会自动完成的。特别是初学者,暂且不要轻举妄动。

##重载模块

以mmmm模块为例(在这里要特别提醒看官:我这样命名是相当不好滴,只不过是为了恶搞才这样命名的)。

在一个shell里面,运行了python,并且做了如下操作:

>>> import mmmm
>>> mmmm.web
'https://qiwsir.github.io'

下面我再打开一个shell,编辑mmmm.py这个文件,进行适当修改:

保存之后,切换到原来的那个导入了模块的交互模式:

>>> mmmm.web
'https://qiwsir.github.io'

输出的跟前面的一样,没有任何变化,这是为什么呢?

原来,当导入模块的时候,只会在第一次导入时加载和执行模块代码,之后就不会重新加载或重新执行了,如果模块代码修改了,但是这里执行的还是修改之前的。

怎么实现代码修改之后,执行新的呢?一种方式就是退出原来的交互模式,再重新进入,再import mmmm。呵呵,这种方法有点麻烦。Python提供了另外一个函数——reload函数,能够实现模块的重新加载(简称重载),重载后模块代码重新执行。如下继续:

>>> reload(mmmm)
<module 'mmmm' from 'mmmm.py'>
>>> mmmm.web
'https://qiwsir.github.io, I am writing a python book on line.'

这下就显示修改之后的内容了。

特别提醒注意:

  • reload是内置函数
  • reload(module),module是一个已经存在的模块,不是变量名。
### Python `importlib.reload` 报错解决方案 在使用 `importlib.reload()` 函数时,可能会遇到类似于以下的错误: ```plaintext TypeError: reload() argument must be a module ``` 此错误表明传递给 `reload()` 的参数不是一个有效的模块对象[^1]。以下是详细的分析和解决方法。 --- #### 错误原因分析 1. **传入的对象不是模块** 根据官方文档说明,`importlib.reload()` 需要接收一个合法的模块对象作为参数。如果传入的是字符串或其他类型的对象,则会引发上述错误[^2]。 2. **模块未正确定义或导入失败** 如果尝试重新加载的模块本身存在问题(例如语法错误),则可能导致无法成功导入模块,从而使得 `reload()` 失败。 3. **Python 版本差异** 在 Python 3 中,`reload()` 被移到了 `importlib` 模块下,而不再像 Python 2 那样可以直接调用 `reload()` 函数。此外,某些旧版代码可能仍然试图直接调用 `reload()`,这会导致 NameError 或 AttributeError[^3]。 --- #### 解决方案 ##### 方法一:确保传入的是有效模块对象 确认传递给 `reload()` 的是一个真正的模块对象,而不是字符串名称。例如: ```python from importlib import reload import yoyo # 假设这是一个已存在的模块 new_yoyo = reload(yoyo) # 正确的方式 ``` 如果尝试通过字符串形式指定模块名,则需要先将其转换为实际的模块对象。可以通过 `sys.modules` 来实现这一点: ```python import sys from importlib import reload if 'yoyo' in sys.modules: new_yoyo = reload(sys.modules['yoyo']) else: raise ImportError("Module 'yoyo' is not imported yet.") ``` --- ##### 方法二:处理模块依赖关系 如果目标模块中有其他子模块或外部依赖项,仅重新加载父模块并不会自动刷新这些依赖项。此时需手动管理依赖链路,或者清除相关条目后再重新加载。例如: ```python import sys from importlib import reload # 清除特定模块及其依赖 for mod_name in list(sys.modules.keys()): if mod_name.startswith('my_module'): del sys.modules[mod_name] # 手动重新导入 import my_module reloaded_my_module = reload(my_module) ``` > 注意:删除 `sys.modules` 中的内容会影响整个程序环境,请谨慎操作[^4]。 --- ##### 方法三:调试与验证模块状态 为了排查问题根源,可以在调用前打印当前模块的状态信息: ```python print(f"Current modules loaded: {list(sys.modules.keys())}") ``` 同时检查是否存在拼写错误、循环引用等问题。 --- #### 示例代码 下面提供一段完整的示例来演示如何安全地使用 `importlib.reload()`: ```python import sys from importlib import reload def safe_reload(module_name): """ 安全地重新加载指定模块。 参数: - module_name (str): 待重载模块的名字 返回值: - reloaded_module: 成功重载后的模块对象;若失败返回 None """ if module_name in sys.modules: original_module = sys.modules[module_name] try: return reload(original_module) except Exception as e: print(f"Failed to reload '{module_name}': {e}") else: print(f"Module '{module_name}' has not been imported.") # 测试用法 safe_reload('yoyo') ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值