模块和包是比类更高一级的代码封装和复用,通过把相似的代码组织在一起使用,可以大量的减少程序的耦合。对于每个模块都有所谓的内部和外部之分,从这种角度来看,模块很像一种类,模块内部的代码属于模块的私有成员,由模块控制,对外暴露接口给外部使用。
为了方便解释,使用spyder创建一个项目,模块的引用就可以很方便的在IPython端使用。
Python的模块在首次导入(import)时,模块就会编译成字节码,也就是pyc文件(python3.2以后就统一存放在__pycache__目录下)。模块会被作为一个实例,为其内部提供一个全局名字空间,在一次的session中,无论模块的源文件是否发生变化,已经初始化后的实例都不会发生变化。先创建一个module.py文件,放入下面代码。
x = "hello world!"
def test():pass
class Test:pass
导入模块:
import module
dir(module)
Out[2]:
['Test',
'__builtins__',
'__cached__',
'__doc__',
'__file__',
'__loader__',
'__name__',
'__package__',
'__spec__',
'test',
'x']
module.x
Out[3]: 'hello world!'
修改module文件变成:
x = "god hate you"
def test():pass
class Test:pass
再次导入文件:
import module
module.x
Out[5]: 'hello world!'
x并没有发生变化。 所以这里牵扯到Python的热更新问题了,标准库提供了importlib.reload方法解决这个问题,但是这个方案缺点在于它并不会递归的修改成员引用(当你模块的成员被其它变量引用时,引用成员并不会发生变化)
import importlib
importlib.reload(module)
Out[9]: <module 'module' from '...\\module.py'>
module.x
Out[10]: 'god hate you'
除此之外,还可以使用__name__获得模块自身的信息。在module模块添加:
print(__name__)
运行本模块,此时__name__返回的是__main__,而直接导入module时会返回模块自身的名字。
runfile('D:/python/huaban/module.py', wdir='D:/python/huaban')
__main__
importlib.reload(module)
module
如果模块里面有些信息,不希望外部看到,可以使用__all__明确指定哪些成员允许被导入。在module.py添加:
__all__ = ["test"]
from module import *
module
dir()
Out[2]:
[...
'test']
这样其它的成员便被隐藏了,和类的私有成员一样,这不是真正的意义权限设置,你还是有办法可以看的到。例如:
import module
dir(module)
Out[5]:
['Test',
'__all__',
'__builtins__',
'__cached__',
'__doc__',
'__file__',
'__loader__',
'__name__',
'__package__',
'__spec__',
'test',
'x']
我们这样就可以看到了module的所有的名字空间。