从小白到小黑 python学习之旅 日常总结 21(模块2 包 软件开发的目录规范)*
python文件的两种用途
1、被当成程序运行
2、被当做模块导入
如何区别二者的用途?
当一个python文件 被运行时,__name__的值为'__main__'

当一个python文件 被当做模块导入时,__name__的值为那个模块的文件名


from-import
from...import...与import语句基本一致
impot导入模块在使用时必须加前缀"模块."
优点:肯定不会与当前名称空间中的名字冲突
缺点:加前缀显得麻烦
from...impot...导入模块在使用时不用加前缀
优点:代码更精简
缺点:容易与当前名称空间混淆
无需加前缀的好处是使得我们的代码更加简洁,坏处则是容易与当前名称空间中的名字冲突,如果当前名称空间存在相同的名字,则后定义的名字会覆盖之前定义的名字。
from ... import ...导入也发生了三件事
1、产一个模块的名称空间
2、运行foo.py将运行过程中产生的名字都丢到模块的名称空间去
3、在当前名称空间拿到一个名字,该名字指向模块名称空间中的某一个内存地址
from foo import func
from...impot...可以一行导入多个名字(不推荐)
from foo import func,get,change
*:导入模块中的所有名字 、__all__ 可以控制*代表的名字有哪些 、起别名
from...impot* #导入模块中的所有名字 __all__=[名字] # 右边列表里的名字 就是*导入模块中的名字 #默认是所有名字 from foo import get as g # 起别名 print(g)
循环导入问题
循环导入问题指的是在一个模块加载/导入的过程中导入另外一个模块,而在另外一个模块中又返
回来导入第一个模块中的名字,由于第一个模块尚未加载完毕,所以引用失败、抛出异常,究其根
源就是在python中,同一个模块只会在第一次导入时执行其内部代码,再次导入该模块时,即便
是该模块尚未完全加载完毕也不会去重复执行内部代码
示例

解析

那么如何解决那


方案一:导入语句放到最后,保证在导入时,所有名字都已经加载过
方案二:导入语句放到函数中,只有在调用函数时才会执行其内部代码
搜索模块的路径与优先级
无论是import还是from...import在导入模块时都涉及到查找问题
优先级:
1、内存(内置模块)
2、硬盘:按照sys.path中存放的文件的顺序依次查找要导入的模块
sys.path
import sys print(sys.path) # 值为一个列表,存放了一系列的文件夹和压缩文件的路径 # 其中第一个文件夹是当前执行文件所在的文件夹的路径
往 sys.path 里加需要导入模块的路径
import sys sys.path.append(r'需要导入模块的路径')
了解:sys.modules查看已经加载到内存中的模块
import sys print(sys.modules) #已经加载到内存中的模块
编写一个规范的模块
#!/usr/bin/env python #通常只在类unix环境有效,作用是可以使用脚本名来执行,而无需直接调用解释器。 "The module is used to..." #模块的文档描述 import sys #导入模块 x=1 #定义全局变量,如果非必须,则最好使用局部变量,这样可以提高代码的易维护性,并且可以节省内存提高性能 class Foo: #定义类,并写好类的注释 'Class Foo is used to...' pass def test(): #定义函数,并写好函数的注释 'Function test is used to…' pass if __name__ == '__main__': #主程序 test() #在被当做脚本执行时,执行此处的代码
函数的类型提示功能(需要python 3.5以上)
: 后跟提示信息 、 __annotations__ 查看提示信息

包
什么是包那
包就是一个包含有__init__.py文件的文件夹
包的本质是模块的模块的一种形式,包是用来被当做模块导入
为何要有包
随着模块数目的增多,把所有模块不加区分地放到一起也是极不合理的,于是Python为我们提供了一种把模块组织到一起的方法,即创建一个包。
强调
在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import
包报错
创建包的目的不是为了运行,而是被导入使用
包的使用
导入包发生的3件事
1、执行包下的__init__.py文件
2、产生一个新的名称空间用于存放__init__.py执行过程中产生的名字
3、在当前执行文件所在的名称空间中得到一个名字pool,该名字指向__init__.py的名称空间,例如http://pool.xxx和pool.yyy中的xxx和yyy都是来自于pool下的__init__.py,也就是说导入包时并不会导入包下所有的子模块与子包
强调
1.关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如import 顶级包.子包.子模块,但都必须遵循这个原则。但对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。
2、包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间
3、import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件
绝对导入与相对导入
绝对导入:以顶级包(包的文件夹)为起始来进行导入
from 顶级包.子模块 import 子模块中的名称 # . 的左边必须是包 不然报错
绝对导入是没有任何限制的,所以绝对导入是一种通用的导入方式
相对导入:.代表当前文件所在的目录,..代表当前目录的上一级目录,依此类推来进行导入
from .子模块 import f1 子模块中的名称 # . 指当前文件夹
仅限于包内使用 ,不能跨出包(包内模块之间的导入,推荐使用相对导入)
相对导入不能跨出包,所以相对导入仅限于包内模板彼此之间闹着玩
如果包从硬盘导入执行文件时所有被导入的模块或者说后续的其他文件引用的sys.path都是参照执行文件的sys.path 而sys.path要有顶级包的路径 所以说绝对导入时是以顶级包为准的
项目执行文件 相对导入不能出本层文件夹 应该用绝对导入 把项目的根目录!动态!加入sys.path (以下是把项目根目录动态加入sys.path)
# print(__file__) # 当前文件的绝对路径 import os import sys os.path.dirname(os.path.dirname(__file__)) # 获取本层文件夹的文件夹 就是上两层 sys.path.append(os.path.dirname(os.path.dirname(__file__))) # 把他导入sys.path里
from 包 import *
* 代表的是包下的__init__.py中所有的名字
至于__all__怎么控制 * (要听egon老湿下回分解)
软件开发的目录规范
#参考(暂时) 项目名称/ |-- core/ #存放核心逻辑相关代码 | |-- src.py | |-- bin/ #存放可执行文件 比如说:启动文件 | |-- start.py | |-- db/ #存放操作数据库相关文件,主要用于与数据库交互 | |-- db_handle.py | |-- lib/ #存放程序中常用的自定义模块 | |-- common.py | |-- conf/ #存放配置文件 | |-- settings.py | |-- log/ #存放日志文件 | |-- user.log | |-- README #存放项目说明

浙公网安备 33010602011771号