一、程序解耦

解耦总的一句话来说,减少依赖,抽象业务和逻辑,让各个功能实现独立。

直观理解“解耦”,就是我可以替换某个模块,对原来系统的功能不造成影响。是两个东西原来互相影响,现在让他们独立发展;核心思想还是最小职责,每个地方都只做一件事情;只要一个地方负责了多项事情,就存在解耦的可能。在系统每个层次都可以体现解耦的思想,比如在架构层面把存储和业务逻辑解耦,把动态页面和静态页面解耦;在模块层面把业务模块和统计模块解耦;在代码层面把多个功能解耦等等。

低耦合,高内聚---模块之间低耦合,模块内部高内聚。一个系统有多个模块组成,在划分模块时,要把功能关系紧密的放到一个模块中(高内聚),功能关系远的放到其它模块中。模块之间的联系越少越好,接口越简单越好(低耦合,细线通信)。

二、模块

概念

在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。在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*行为的角色

Python之路(第十二篇)程序解耦、模块介绍\导入\安装、包的更多相关文章

  1. Python之路(第二十二篇) 面向对象初级:概念、类属性

    一.面向对象概念 1. "面向对象(OOP)"是什么? 简单点说,“面向对象”是一种编程范式,而编程范式是按照不同的编程特点总结出来的编程方式.俗话说,条条大路通罗马,也就说我们使 ...

  2. Python开发【第二十二篇】:Web框架之Django【进阶】

    Python开发[第二十二篇]:Web框架之Django[进阶]   猛击这里:http://www.cnblogs.com/wupeiqi/articles/5246483.html 博客园 首页 ...

  3. Python之路(第十六篇)xml模块、datetime模块

    一.xml模块 xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单, xml比较早,早期许多软件都是用xml,至今很多传统公司如金融行业的很多系统的接口还主要 ...

  4. Python之路【第七篇】:常用模块

    一. 模块介绍 1. 什么是模块 在前面的几个章节中我们基本上是用 python 解释器来编程,如果你从 Python 解释器退出再进入,那么你定义的所有的方法和变量就都消失了. 为此 Python ...

  5. Python之路【第四篇】:模块

    什么是模块: 模块就是一个功能的集合. 模块就和乐高积木差不多,你用这些模块组合出一个模型,然后也可以用这个模块加上其他的模块组合成一个新的模型 模块的种类: 1.内置模块(python自带的比如os ...

  6. Python之路【第三篇】:模块

    定义: 包:包含__init__.py文件.模块(也是.py文件) 当包被其它模块调用时,首先会执行该包下的__init__文件 包含有模块,包可以有多级 模块的导入: import from...i ...

  7. Python学习【第十二篇】模块(2)

    序列化 1.什么是python序列化? 把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling 序列化就是将python的数据类型转换成字符串 反序列化就是将字符串转换成 ...

  8. Python之路(第二十九篇) 面向对象进阶:内置方法补充、异常处理

    一.__new__方法 __init__()是初始化方法,__new__()方法是构造方法,创建一个新的对象 实例化对象的时候,调用__init__()初始化之前,先调用了__new__()方法 __ ...

  9. Python之路(第二十八篇) 面向对象进阶:类的装饰器、元类

    一.类的装饰器 类作为一个对象,也可以被装饰. 例子 def wrap(obj): print("装饰器-----") obj.x = 1 obj.y = 3 obj.z = 5 ...

随机推荐

  1. python全栈开发 随笔 'is' 和 == 的比较知识与区别 编码和解码的内容及转换

    python 一. is 和 == 的区别; == 比较的是两边的值. a = 'alex' b = 'alex' print(a = b) #True a = 10 b = 10 print(a = ...

  2. 单点登录(SSO)解决方案之 CAS服务端数据源设置及页面改造

    接上篇 单点登录(SSO)解决方案之 CAS 入门案例 服务端数据源设置: 开发中,我们登录的user信息都是存在数据库中的,下面说一下如何让用户名密码从我们的数据库表中做验证. 案例中我最终把cas ...

  3. SpringMVC包括哪些组件

      1 映射器 1.1作用:Handlermapping根据url查找Handler   2 适配器 2.1作用:HandlerAdapter执行Handler   3 解析器 3.1作用:View ...

  4. [Android] TextView长按复制实现方法小结(转载)

    这是别人写的,既然别人总结过了,那我就不花时间研究这个了,但往后会补充一些使用经验之类的 原文地址:http://blog.csdn.net/stzy00/article/details/414778 ...

  5. OSPF网络类型不一致路由无法计算的问题

    晚上割接,远端的ASR9001-s网络类型为广播类型,本端为6509-e,网络接口类型修改成p2p后,OSPF邻居关系建立,但是路由无法计算.

  6. 【linux】进程状态

    [进程状态转移图] PROCESS STATE CODES R running or runnable (on run queue) D uninterruptible sleep (usually ...

  7. openal支持的通道数和声道数

    alext.h:  #define AL_FORMAT_QUAD8 0x1204 101 #define AL_FORMAT_QUAD16 0x1205 102 #define AL_FORMAT_Q ...

  8. 项目总结07:JS图片的上传预览和表单提交(FileReader()方法)

    JS图片的上传预览和表单提交(FileReader()方法) 一开始没有搞明白下面这块代码的,今天有时间简单整理下 核心点:FileReader()方法 以下是代码(以JSP文件为例) <!DO ...

  9. django的 信号

    1.信号,其实就是钩子,可以在上面几种情况下定义执行某个函数,我们一般在project的__init__文件中定义,下面就是一个例子 2.用到模块需要导入,分别在下面的几个路径中 from djang ...

  10. String.format的用法

    有些时候,对于一些东西,不是没有简单的方法,而是我们没有接触到过 String.format();即创建格式化的字符串,里面有很多的通配使用符号,我这里说一下我接触到的,以后接触到其他的再填坑 它的内 ...