python学习笔记之模块化
模块化
基本概念
- 在python中,模块、包和库的概念并没有那么清晰
- 一个文件就是一个模块,模块名就是文件名
- 一个目录,包含了
__init__.py
就是一个包 - 通常的当一个包或者若干包,包含一个
setup.py
就认为是一个可分发的库
导入模块
导入模块有两种方式,如下:
import module
from module import submodule
这两种导入方式的命名空间是不同的,以一个例子说明,如下:
1 | import os |
1 | os.path.basename('/usr/local/etc') |
'etc'
1 | from os import path |
1 | path.basename('usr/local/etc') |
'etc'
1 | from os.path import basename |
1 | basename('usr/local/etc') |
'etc'
1 | import os.path |
上边的多种引用模块的方式都可以让我们使用basename
,但各自的命名空间不一样。
重命名
引入模块的重命名用as
语法,看下边的例子:
1 | from os.path import basename as os_basename |
1 | os_basename('/usr/local/etc') |
'etc'
当然直接用import
导入模块时也可以用as
语法:
1 | import sys as system |
这样sys模块的名称被重命名为system了
当一个模块被导入时,真正发生了什么呢?看下边的例子:
1 | (pythv_3.5.1) [root@nod3 learning]# pwd |
1 | (pythv_3.5.1) [root@nod3 learning]# cat foo.py |
1 | (pythv_3.5.1) [root@nod3 learning]# python3 main.py |
在main.py
文件中用import foo
的方式导入了foo
模块,接着再调用了foo
模块的bar
函数,当执行main.py
文件时,首先执行了foo
模块的print('ha ha ha')
语句,再执行了bar
函数。
这说明当导入一个模块时,其实是执行了此模块,所以当一个文件是以模块的形式被导入时,应避免此模块中有一些全局性的语句,比如这时的print('ha ha ha')
语句。
用from foo import bar
的导入方式也是执行了foo
文件,作如下验证:
1 | (pythv_3.5.1) [root@nod3 learning]# cat main.py |
1 | (pythv_3.5.1) [root@nod3 learning]# python3 main.py |
相对导入和绝对导入
在接下来的代码示例不再方便使用jumper来展示,开始用pycharm开发工具来展示代码。
为了说明模块的相对导入和绝对导入,在pycharm中创建了一个reference
包,包内有bar.py
和foo.py
两个模块,在reference
包外有一个main.py
模块。目录结构如下图:
各个模块中的内容如下:
1 | def fn(): |
1 | from reference.foo import fn |
1 | from reference.bar import bar |
当运行main.py
时会得到下边的输出内容:
1 | i am in reference.foo |
上边的bar.py
和main.py
模块中的from
语句都是从包名reference
这里开始引用的,这种引用就是绝对引用
。
因foo.py
和bar.py
两个模块都是在包reference
内,所以bar.py
里引用foo
模块时可以使用相对引用的方式,如下:
1 | from .foo import fn |
这样就是相对引用
的方式。
循环导入
在实际编码中要避免循环导入的,举一个例子说明什么是循环引入。
假如foo.py、bar.py、main.py,这三个模块都在同一个包内,各自的代码如下:
1 | from bar import fn as bar |
1 | from foo import fn as foo |
1 | from foo import fn |
当运行main.py时,抛出以下异常:
1 | Traceback (most recent call last): |
上边的foo模块和bar模块就发生了循环引用的情况,这样在执行main.py时,解释器就会抛出上边的异常信息。