一、程序解耦
解耦总的一句话来说,减少依赖,抽象业务和逻辑,让各个功能实现独立。
直观理解“解耦”,就是我可以替换某个模块,对原来系统的功能不造成影响。是两个东西原来互相影响,现在让他们独立发展;核心思想还是最小职责,每个地方都只做一件事情;只要一个地方负责了多项事情,就存在解耦的可能。在系统每个层次都可以体现解耦的思想,比如在架构层面把存储和业务逻辑解耦,把动态页面和静态页面解耦;在模块层面把业务模块和统计模块解耦;在代码层面把多个功能解耦等等。
低耦合,高内聚---模块之间低耦合,模块内部高内聚。一个系统有多个模块组成,在划分模块时,要把功能关系紧密的放到一个模块中(高内聚),功能关系远的放到其它模块中。模块之间的联系越少越好,接口越简单越好(低耦合,细线通信)。
二、模块
概念
在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。在Python中,一个.py文件就称之为一个模块(Module)。
使用模块的好处
最大的好处是大大提高了代码的可维护性;其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。
模块的种类
python标准库
第三方模块
应用程序自定义模块:自定义模块时要注意命名,不能和Python自带的模块名称冲突。
模块的导入方法
import
import module1
import 模块名,一般是导入python的内置模块
import as
import multiprocessing as mul
在之后的代码中就可以直接用mul.方法名了,不用写长长的multiprocessing.方法名
from…import 语句
from modname import name1[, name2[, ... nameN]]
from 模块 import 方法名 ,这个声明不会把整个modulename模块导入到当前的命名空间中,只会将它里面的name1或name2单个方法引入到执行文件里
from…import* 语句
from modname import *
这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。大多数情况, Python程序员不使用这种方法,因为引入的其它来源的命名,很可能覆盖了已有的定义。
注意:
模块一旦被导入,即相当于执行了一个.py文件(导入模块所在的文件)里的代码
import的工作机制
import语句导入指定的模块时会执行3个步骤
1.找到模块文件:在模块搜索路径下搜索模块文件
程序的主目录
PYTHONPATH目录
标准链接库目录
2.编译成字节码:文件导入时会编译,因此,顶层文件的.pyc字节码文件在内部使用后会被丢弃,只有被导入的文件才会留下.pyc文件
3.执行模块的代码来创建其所定义的对象:模块文件中的所有语句从头至尾依次执行,而此步骤中任何对变量名的赋值运算,都会产生所得到的模块文件的属性(所以自定义函数不要和模块中的名称重合)
不同目录类型的模块文件导入
1、与执行文件同目录模块导入
文件目录结构如下
test.py是执行文件,想调用manage.py模块
可以直接用
import manage
或者
from manage import *
2、不同文件目录的模块导入
M2
├── bin
│ ├── __init__.py
│ └── start.py [程序入口]
├── conf
│ ├── __init__.py
│ └── settings.py
├── core
│ ├── __init__.py
│ ├── accounts.py
│ ├── db_handler.py
│ ├── logger.py
│ ├── main.py
│ └── transaction.py
├── test.py
start.py是执行文件,不同目录下面入口程序得目录加载到sys.path即环境变量中,就可以跨模块调用了
在settings.py 里加入
import sys,os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
这里os.path.abspath(__file__)获取返回settings.py规范化的绝对路径(包含文件),
os.path.dirname(os.path.abspath(__file__))
获取当前运行脚本的绝对路径(去掉最后一个文件),
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
获取当前运行脚本的绝对路径(去掉最后一个路径)
注意的一点是:直接用路径添加sys.path.append()添加目录时注意是在windows还是在Linux下,windows下需要‘\’否则会出错。
此时的模块搜索的主目录是 */M2/,即在M2文件夹下搜索
需求1:
mian.py想要引用accounts模块下的函数需要
from core import accounts
也可以这样写
from . import accounts
从当前目录导入模块(但是这里添加的搜索主目录是上级目录,即这个例子的M2文件夹)
需求2:
main.py 想要引用settings模块需要
from conf import settings
需求3:
test.py想要引用logger.py模块需要
from core import logger
from ..proj import hello (待补充)
注意:python使用. .. 相对导入模块要满足两个条件:
1.文件夹中必须有__init__.py文件
,该文件可以为空,但必须要有
2.不能作为顶层模块来执行该文件夹中得py文件(即不能作为主函数得入口) 意思:..后不能到主函数入口得目录下
多层目录的模块导入
例子
index.py位置为D:\test_package\a\b\c\index.py
文件目录树
D:.
│ test.py
│ __init__.py
│
├─a
│ │ __init__.py
│ │
│ ├─b
│ │ └─c
│ │ index.py
│ │ __init__.py
│ │
│ └─__pycache__
│ __init__.cpython-36.pyc
│
└─__pycache__
test.py想要导入index模块需要
from a.b.c import index
内置变量: __file__
表示当前的文件名
os.path.abspath(path) :返回path的绝对路径
os.path.dirname(path) :返回path的目录(去掉最后一级目录或文件)
例子
index.py文件位置为D:\python\exercise\test_package\b\index.py
在index.py写入
import os
BASE_DIR0 =os.path.abspath(__file__)
BASE_DIR1 = os.path.dirname(os.path.abspath(__file__)) #去掉最后一个文件,返回路径
BASE_DIR2 = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))#去掉最后一级目录返回路径
print(BASE_DIR0)
print(BASE_DIR1)
print(BASE_DIR2)
print("这里是index")
运行输出结果
D:\python\exercise\test_package\b\index.py
D:\python\exercise\test_package\b
D:\python\exercise\test_package
这里是index
if __name__
== '__main__
':
一个模块文件可以直接执行或被导入
每个模块都有一个名为__name__
的内置变量,此变量值会根据调用此模块的方式发生变化:\1. 如果此文件被作为模块导入,则__name__
的值为模块名称\2. 如果此文件被直接执行,则__name__
的值为“__main__
”
我们在创建模块时,在尾部添加如下代码进行模块的自我测试if __name__
== '__main__
':
...
如果模块被导入,则 if 后的语句就不会执行
安装第三方模块
安装第三方模块有两种方式:
1.通过包管理工具pip完成的
即pip install 模块名或者pip3 install 模块名
注意:Mac或Linux上有可能并存Python 3.x和Python 2.x,因此对应的pip命令是pip3
2.下载源码=> 解压源码=> 进入目录
源码格式大概都是 zip 、 tar.zip、 tar.bz2格式的压缩包。解压这些包,进入解压好的文件夹,通常会看见一个 setup.py 的文件。打开命令行,进入该文件夹。
python setup.py install
三、包
包一个文件夹下有多个.py文件,加上__init__空
文件,这个文件夹就是一个包了
包是一个有层次的文件目录结构,它定义了一个由模块和子包组成的Python应用执行环境
基于包,Python在执行模块导入时可以指定模块的导入路径 import pack1.pack2.mod1
每个包内都必须有__init__.py
文件,可包含python代码,但通常为空,仅用于扮演包初始化、替目录产生模块命名空间以及使用目录导入时实现from*行为的角色