python的模块化

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
2
3
4
5
(pythv_3.5.1) [root@nod3 learning]# pwd
/root/virtual_env/fourth_week/learning

(pythv_3.5.1) [root@nod3 learning]# ls
foo.py main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(pythv_3.5.1) [root@nod3 learning]# cat foo.py 
#!/root/.pyenv/versions/pythv_3.5.1/bin/python
# _*_ coding:utf8 _*_


print('ha ha ha')

def bar():
print('i am bar in foo')

(pythv_3.5.1) [root@nod3 learning]# cat main.py
#!/root/.pyenv/versions/pythv_3.5.1/bin/python
# _*_ coding:utf8 _*_


import foo

foo.bar()
1
2
3
(pythv_3.5.1) [root@nod3 learning]# python3 main.py 
ha ha ha
i am bar in foo

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
2
3
4
5
6
7
(pythv_3.5.1) [root@nod3 learning]# cat main.py 
#!/root/.pyenv/versions/pythv_3.5.1/bin/python
# _*_ coding:utf8 _*_


from foo import bar

1
2
(pythv_3.5.1) [root@nod3 learning]# python3 main.py 
ha ha ha

相对导入和绝对导入

在接下来的代码示例不再方便使用jumper来展示,开始用pycharm开发工具来展示代码。

为了说明模块的相对导入和绝对导入,在pycharm中创建了一个reference包,包内有bar.pyfoo.py两个模块,在reference包外有一个main.py模块。目录结构如下图:

目录结构

各个模块中的内容如下:

foo.py:

1
2
def fn():
print('i am in reference.foo')

bar.py:

1
2
3
4
5
from reference.foo import fn


def bar():
fn()

main.py:

1
2
3
from reference.bar import bar

bar()

当运行main.py时会得到下边的输出内容:

1
i am in reference.foo

上边的bar.pymain.py模块中的from语句都是从包名reference这里开始引用的,这种引用就是绝对引用

foo.pybar.py两个模块都是在包reference内,所以bar.py里引用foo模块时可以使用相对引用的方式,如下:

bar.py:

1
2
3
4
5
from .foo import fn


def bar():
fn()

这样就是相对引用的方式。

循环导入

在实际编码中要避免循环导入的,举一个例子说明什么是循环引入。

假如foo.pybar.pymain.py,这三个模块都在同一个包内,各自的代码如下:

foo.py:

1
2
3
4
5
6
from bar import fn as bar


def fn():
bar()
print('i am foo')

bar.py:

1
2
3
4
5
6
from foo import fn as foo


def fn():
foo()
print('i am bar')

main.py:

1
2
3
from foo import fn

fn()

当运行main.py时,抛出以下异常:

1
2
3
4
5
6
7
8
Traceback (most recent call last):
File "D:/pythonlearning/fourth_week/reference/main.py", line 1, in <module>
from foo import fn
File "D:\pythonlearning\fourth_week\reference\foo.py", line 1, in <module>
from bar import fn as bar
File "D:\pythonlearning\fourth_week\reference\bar.py", line 1, in <module>
from foo import fn as foo
ImportError: cannot import name 'fn'

上边的foo模块和bar模块就发生了循环引用的情况,这样在执行main.py时,解释器就会抛出上边的异常信息。

文章目录
  1. 1. 模块化
    1. 1.1. 基本概念
    2. 1.2. 导入模块
    3. 1.3. 重命名
  2. 2. 相对导入和绝对导入
    1. 2.1. 循环导入
|