Learning Python Part III 之 模块的重载

来源:互联网 发布:淘宝达人官网 编辑:程序博客网 时间:2024/06/06 12:44

正如之前所说,默认情况下一个模块的代码在每个进程中只运行一次。如果要强制要求一个模块的代码被重新加载和运行,你需要调用内置函数reload,概括的来讲:

  • Import(包括import和from)在每个进程中仅仅在第一次被导入时加载和运行模块的代码
  • 之后的导入直接使用已经加载的模块对象,而不需要重新加载和运行模块代码
  • reload函数会强制将已经已经加载的模块文件被重新加载和运行,赋值会直接改变已经存在的模块对象。

为什么需要关注模块重载?简单来说,动态定制reload函数允许程序的一部分被改变,而不需要停止整个程序的运行。通过reload,改变一个组件对整个程序的影响可以被立即观察到。重载并不是在每个情况下都很有用,但在有些情况下会大大缩短开发周期。比如,想象一下一个数据库程序在每次启动时都必须链接服务器;有了重载,在程序改变之后可以立即测试,在debug的时候你只需要连接一次。长时运行的服务器也可以用这种方法更新。
不过需要注意的是reload仅仅对用Python写的模块有效;用其他语言(例如C语言)编写的已编译的扩展模块在编译时可以被动态的加载,但它们不能够重载!

reload基础

importfrom不同:

  • reload在Python中是一个函数,而不是语句
  • reload被传递的是一个已经存在的模块对象,而不是一个新名字
  • 在Python3.X中reload是在一个模块中,必须要先导入

因为reload接受的参数是模块对象,所以重载的模块必须之前被导入过,整个大致的流程就像这样:

import module  #导入模块...use module.attributes.........from imp import reload   #导入reload所在的模块reload(module)...use module.attributes...

典型的使用模式就是:你先导入一个模块,然后在一个编辑器中改变源代码,然后重载。
当调用reload的时候,Python重读模块文件的源代码,重运行它的最高层级的语句。不过很值得注意的是reload是直接改变模块对象;它并不是删除和重建模块对象。正因为此,任何的在程序中任何地方的对模块对象的引用都会被重载立即影响:

  • reload在当前对象的命名空间中运行模块的新代码,重新运行一个模块的代码会重写已经存在的命名空间而不是删除后重建。
  • 文件中最高层级的赋值语句会更新值,例如,重新运行def语句会通过重新赋值函数名来取代模块命名空间中之前版本的函数。
  • Import会被重载影响,通过import取得模块的属性,在重载之后会在模块对象中发现新的值。
  • From不会被重载影响,在之前通过from取得模块的属性在重载之后不会被影响,仍然会有一个引用指向旧的对象属性。
  • reload每次只能应用于一个模块

reload例子

在这个例子中,我们会不停止程序并改变和重载一个模块文件:

首先在编辑器中创建一个包含一下内容的模块文件 changer.py
message = "First version"def printer():    print(message)
这个模块创建个输出了两个名字——一个连接字符串,另一个指向函数。然后启动Python解释器,导入模块,调用函数:
>>> import changer>>> changer.printer()First version
不要关闭解释器,在另一个窗口中编辑模块文件,改成以下内容:
message = "After editing"def printer():    print('reloaded:', message)
然后返回解释器并重新导入模块,然后重载:
>>> import changer>>> changer.printer()First version>>> from imp import reload>>> reload(changer)       # Forces new code to load/run<module 'changer' from '.\\changer.py'>>>> changer.printer()     # Runs the new version nowreloaded: After editing

最后两个需要注意个点:首先,如果使用reload,最好相对应的使用import而不是from,因为后者不会被重载改变——这会把你的变量留在一个很奇怪的状态。其次,重载只会更新一个模块,但我们也可以写一个函数将它传递应用到相关的模块。