C:\Program Files\Python310\Lib
1、 包的概念:把解决同一类问题的模块放在同一个文件夹里,我们就称为包。
2、在PyCharm中创建一个包:
文件夹中会有一个init.py文件。
在Python3中没有这个__init__.py文件也没有问题。
3、在包A和包B下有同名模块也不会发生冲突,如A.a与B.a来自两个命名空间:
import os
os.makedirs('glance/api') # 在当前目录,创建多级目录
os.makedirs('glance/cmd')
os.makedirs('glance/db')
l = []
l.append(open('glance/__init__.py', 'w')) # 把文件句柄append到列表中
l.append(open('glance/api/__init__.py', 'w'))
l.append(open('glance/api/policy.py', 'w'))
l.append(open('glance/api/versions.py', 'w'))
l.append(open('glance/cmd/__init__.py', 'w'))
l.append(open('glance/cmd/manage.py', 'w'))
l.append(open('glance/db/__init__.py', 'w'))
l.append(open('glance/db/models.py', 'w'))
map(lambda f: f.close(), l) # 最后通过map来统一关闭列表里的文件
#文件内容
#policy.py
def get():
print('from policy.py')
#versions.py
def create_resource(conf):
print('from version.py: ',conf)
#manage.py
def main():
print('from manage.py')
#models.py
def register_models(engine):
print('from models.py: ',engine)
将这些内容分别放到各个文件中。
注意事项:
1)包相关的导入语句也分为import和from...import...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但是都必须遵循这一个原则。
2)对于导入后,在使用时就没有这个限制了,点的左边可以是包、模块、函数、类(它们都可以用点的方法调用自己的属性)。
3)对比import item和from item import name的应用场景:
如果我们想直接使用name,那必须使用后者。
然后,我们在与包glance同级的01homework.py文件中测试:
# 01homework.py
# import语句
# import glance.api.policy
# glance.api.policy.get()
# from...import...
from glance.api import policy
policy.get()
#
from glance.api.policy import get
get()
结果:
需要注意的是from后import导入的模块,必须是明确的一个不能带点,否则会有语法错误,如:from a import b.c,就是错误语法。
我们再看下另外一个问题:
glance目录是在day2这个目录下面。我们的文件01homework.py文件是跟glance目录是同级的,都是在day2这个目录下面。我们查看sys.path的信息,看到解释器查找目录路径就是直接到day2这个目录中查找,在这个目录中,如果找不到glance目录,那pycharm编辑器将提示出错。
我们也可以通过sys.path.insert()函数将新的查找路径添加到sys.path中去,这样处理也是可以的。
然后我们再看一个文件__init__.py:
不管是哪种方式,只要是第一次导入包或者是包的任何其他部分,都会依次执行包下的__init__.py文件(我们可以在每个包的文件内都打印一行内容来验证一下),这个文件可以为空,但是也可以存放一些初始化包的代码。
单独导入包名的时候,不会导入包中所有包含的所有子模块。
那我们现在直接导入glance包,实现这个功能,就是希望得到glance包中所有模块的功能:
import glance
glance.api.policy.get() # 那这样,glance包中的各个子目录的文件中的方法就都能使用了
实现这个效果,那我们利用__init__.py文件的特性,需要在glance目录和子目录中的__init__.py文件进行一些处理:
这个是绝对导入:
# glance/__init__.py
from glance import api
from glance import cmd
from glance import db
# glance/api/__init__.py
from glance.api import policy
from glance.api import versions
# glance/cmd/__init__.py
from glance.cmd import manage
# glance/db/__init__.py
from glance.db import models
然后我们再测试下:
import glance
glance.api.policy.get()
glance.db.models.register_models('mysql')
相对路径:
. 点表示的是当前目录:
.. 两点表示的是上一级目录。
这个是相对导入:
# glance/__init__.py
from . import api
from . import cmd
from . import db
# glance/api/__init__.py
from . import policy
from . import versions
# glance/cmd/__init__.py
from . import manage
# glance/db/__init__.py
from . import models
我们把绝对路径改成了点号,表示当前目录。然后再进行下测试,测试也是正常的。
那我们可以将glance随意移动到别的目录中,只要能找到包的位置,就可以使用包里的模块了。
但是这个时候,我们在这个包里的模块之间调用模块功能就发生错误,因为我们是使用的相对路径,我们在里面的模块又使用了绝对路径,就出现错误。然后我们使用相对路径,只能有..号,相对路径返回上一级。
我们在glance包外边使用就是正常的。
目前,我们这个阶段还没有到制作包的阶段。
我们目前使用这个包,我们正常是使用包里的模块,只要熟悉这个模块的功能即可,正常情况下是不需要到模块中相互调用的。
另外,我们还有*和__all__配合的方式:因为__all__是用于控制from ... import * 的。
注意:在使用pycharm时,有的情况会为你多做一些事情,这是软件相关的东西,会影响你对模块的理解,因而在测试的时候,一定要回到命令行去执行,模拟我们的生产环境。
特别主要注意的是:可以用import导入内置或者第三方模块,但是要绝对避免使用import来导入自定义包的子模块,应该使用from...import...的绝对或者相对导入,且包的相对导入只能用from的形式。
最后有一个软件开发规范:
非web项目的规格:
说明:
1)bin目录下要写一个开始文件,程序入口;
if __name__ == '__main__':
core.main()
2)core目录,所写的代码都放在这个目录中;
3)conf目录:配置文件,配置文件是给运维人员看的,调一些参数。
4)db目录,userinfo的文件,json文件;
5)lib目录,通用的模块,没有自动安装到python解释器中,这是我们自己写的通用模块;
6)log目录:是我们程序运行的过程,中间执行的每一个结果都显示出来;中间执行结果记录到文件中,有问题去查文件。