模块和包
一、import 模块
import一个模块相当于执行了这个模块,导入模块后可以使用模块中的属性和方法,比如模块名.变量、模块名.函数
当前模块和被导入模块是存在两个不同的内存空间
import模块的原理:
① 寻找模块
② 找到模块就开辟一块空间,来执行这个模块
③ 把这个模块中用到的名字都收录到新开辟的空间中
④ 创建一个变量来引用这个模块的空间
导入模块注意点:
① 一个模块不能被重复导入
② 模块和模块之间的内存空间始终是隔离的
③ 模块的名字必须符合变量的命名规则,否则无法导入
④ 被导入模块的方法只会找到它自己的模块空间的属性
⑤ 一行只能导入一个模块(符合PEP8规范)
可以给导入的模块起别名,但起了别名以后,原来的模块名就不能使用了。
起别名的原理:找到这个模块,用别名指向它,所以原模块名跟模块没关系了
import XXX as X
# mymodule.py
a = 1
def func():
print(222)
# main.py
import mymodule as m
print(m.a)
m.func()
模块的搜索路径:
执行一个文件,依靠的是sys.path
pycharm会将项目的目录放进去,但是运行程序有时并不在pycham,
目前python会及那个当前文件的目录导进来,然后再导入项目
正常的sys.path中除了内置、扩展模块所在的路径之外
只有一个路径是永远不会出现问题,直接执行的这个文件所在的目录
一个模块能否被导入,就看这个模块所在的目录在不在sys.path中
两种运行py文件的方式:
① 直接运行:cmd下 python xxx.py
以脚本的形式去运行,__name__ == '__main__'
② 导入模块
__name__ == '模块名'
if __name__ == '__main__'
当一个文件作为一个脚本又作为一个模块,作为模块的时候将打印的东西放在 if __name__ == '__main__' 逻辑里
所有的打印逻辑和函数的调用,都放在 if __name__ == '__main__' 的逻辑内,一旦导入模块的时候,if的内容不会执行
二、from... import ...
① from 模块 import 变量/方法
找到模块,开辟空间执行模块
所有的模块里的属性和方法都存储的模块的所属的空间中
在全局命名空间创建一个变量名/方法名分别指向模块中的名字
# mymodule.py
a = 1
def func():
print(222)
# main.py
from mymodule import a
print(a)
② from 模块 import *
相当于把模块的所有方法、变量导入到当前的全局命名空间中。
一般情况下,使用的变量超过5个就使用星号
在模块中添加了 __all__, 把模块里能用的变量或者方法放在__all__中,但all只能跟*配合使用
# mymodule.py
__all__ = ['a','b'] # 如果导入的是星号,只能使用a、b两个变量,不能使用方法
a = 1
b = 2
def func():
print(222)
def func2():
print(333)
# main.py
from mymodule import * # 只能使用模块里__all__定义的内容
func()
print(a)
# 报错,NameError: name 'func' is not defined
三、模块的补充:
① pyc文件、pyi文件
pyi文件是跟py一样文件,只是后缀名不一样,里面也是python的代码
pyc是编译好的字节码文件,但一个模块当作模块执行的时候,会产生一个pyc文件,下次导入模块的时候,会直接使用pyc文件,假如在下次调用前模块修改过,那么才会再产生一个pyc文件
pyc文件提高程序的启动效率并不能提高程序的执行效率,pyc文件再启动的时候会产生,如果要提高启动效率,提前先执行python程序
② 模块的导入和修改
导入模块后,在执行程序中修改模块的内容,源程序不会使用修改后的值,就算重新导入模块也不会使用修改后的值
解决方法(不建议使用):
from importlib import reload
reload(模块名)
③ 模块的循环引用
A import B
B import A
循环引用会报错,在程序中不要发生循环引用的问题,只能是单向引用,不能成环。
④ dir(模块名)
dir(模块名) 获取模块的是所有方法和属性,用反射的方式来调用
四、包
python3中的Directory和package都带__init__.py的文件
含有一个__init__.py的文件夹就是一个包
python2中没有__init__.py文件就不能导入模块了,但是可以手动创建__init__.py,这样就变成了一个包
从包中导入模块:
imprt XXX.XXX.XXX
点的左边必须是一个包,终点必须是一个模块,精确到具体的模块
from ... import ...
一般情况:from 包 import 模块
导入包:
导入包的过程相当于执行了这个包的__init__.py文件
作为一个包,所有包内的文件的导入都要考虑sys.path的问题(相对导入了这个问题)
sys.path中的内容 永远是当前执行的文件
绝对路径导入优点:能看清楚目录的层次关系
绝对路径导入缺点:每次移动都要修改绝对导入路径
glance/
├── __init__.py from glance import api
from glance import cmd
from glance import db
├── api
│ ├── __init__.py from glance.api import policy
from glance.api import versions
│ ├── policy.py
│ └── versions.py
├── cmd from glance.cmd import manage
│ ├── __init__.py
│ └── manage.py
└── db from glance.db import models
├── __init__.py
└── models.py
相对路径导入
. 表示当前目录
.. 表示上一层目录
glance/
├── __init__.py from . import api #.表示当前目录
from . import cmd
from . import db
├── api
│ ├── __init__.py from . import policy
from . import versions
│ ├── policy.py
│ └── versions.py
├── cmd from . import manage
│ ├── __init__.py
│ └── manage.py from ..api import policy
#..表示上一级目录,想再manage中使用policy中的方法就需要回到上一级glance目录往下找api包,从api导入policy
└── db from . import models
├── __init__.py
└── models.py
相对导入
如果带着相对路径导入的文件,就不能被执行,只能是当作模块导入。
相对路径导入一般是给包外的文件提供服务,包内的文件不能执行,运用了相对路径导入的文件不能被执行。
五、项目目录规划
项目名称的文件夹
bin 文件夹 (只能由start.py 文件,只有一个文件,而且名字不能改变)
start.py # 负责项目的启动
conf 文件夹 (配置文件的目录,文件都要统一格式)
config.ini
settings.py(推荐使用)
core 文件夹 (存放的是核心代码)
db 文件夹 (存放的是数据文件,不是py文件)
lib 文件夹 (存放库文件,放第三方模块或者自定义模块)
log 文件夹 (存放的是log文件)
log