*1 什么是模块*
模块就是一系列功能的集合体
模块有三种来源
1. 内置的模块
2. 第三方的模块
3. 自定义模块
模块的格式:
1 使用python编写的.py文件(常用)
2 已被编译为共享库或DLL的C或C++扩展
3 把一系列模块组织到一起的文件夹(注:每一个包目录下面都会有一个*init*.py 的文件,这个文件是必须存在的,否则,Python 就把这个目录当成普通目录,而不是一个包。*init*.py 可以是空文件,也可以有 Python 代码,因为*init*.py 本身就是一个模块,而它的模块名就是 mycompany)
4 使用C编写并链接到python解释器的内置模块
*2 为何要用模块*
1. 使用内置的或者第三方模块的好处是: 拿来主义,可以极大提升开发效率
2. 使用自定义模块的好处是: 可以减少代码冗余(抽取我们自己程序中要公用的一些功能定义成模块,然后程序的各部分组件都去模块中调用共享的功能)
*3 如何用模块*
大前提: 一定要区分开谁是执行文件,谁是被导入模块
_*import*_
例:
#spam.py
money=1000
def read1():
print('spam模块:',money)
def read2():
print('spam模块')
read1()
def change():
global money
money=0
文件名是spam.py,模块名则是spam
*首次导入模块发生3件事*
1. _会产生一个模块的名称空间_
2. _执行文件spam.py,将执行过程中产生的名字都放到模块的名称空间中_
3. _在当前执行文件的名称空间中拿到一个模块名,该名字指向模块的名称空间_
_之后的导入,都是直接引用第一次导入的成果,不会重新执行文件_
import spam
# 之后引用的同名模块不会再重复执行
import spam
import spam
import spam
*在执行文件中访问模块名称空间中名字的语法:模块名.名字*
import spam
print(spam.x) # 指名道姓地跟spam要名字x,肯定不会与当前执行文件中的名字冲突
*总结*
import导入模块:在使用时必须加上前缀:模块名.
优点: _指名道姓地向某一个名称空间要名字,肯定不会与当前名称空间中的名字冲突_
缺点: _但凡应用模块中的名字都需要加前缀,不够简洁_
* 一行导入多个模块(不推荐)
import spam, os, time
* 可以为模块起别名(注意:模块名应该全为小写)
import spam as sm
_form .. import .._
例:
#spam.py
__all__ = ['money','read1'] #from spam import *
money=1000
def read1():
print('spam模块:',money)
def read2():
print('spam模块')
read1()
def change():
global money
money=0
money=200
*首次导入模块发生3件事*
1. _创建一个模块的名称空间_
2. _执行文件spam.py,将执行过程中产生的名字都放到模块的名称空间中_
3. _在当前执行文件中直接拿到一个名字,该名字就是执行模块中相对应的名字的_
from spam import money,read1,read2,change
money=200
print(money)
read1=123
read1()
read2()
change()
print(money)
*总结*
from...import...
优点: _使用时,无需再加前缀,更简洁_
缺点: _容易与当前名称空间中的名字冲突_
from spam import * 代表从被导入模块中拿到所有名字(不推荐使用)
# from spam import money,read1,read2,change
# from spam import # *all* = ['money','read1']
print(money)
print(read1)
print(read2)
print(change)
起别名 from spam import read1 as r1
r1()
内容:
1. 模块的循环导入
2. 区分python文件的两种用途
3. 模块的搜索路径
4. 模块的绝对导入
5. 模块的相对导入
6. 软件开发的目录规范
'''
首次导入模块发生的三件事
1. 产生一个模块的名称空间
2. 执行被导入模块的代码,将产生的名字全都放在模块的名称空间里
3. 当执行文件时,拿到一个被导入模块的名字,这个名字就指向被导入模块的名称空间的那个名字
'''
*第二次再导入相同模块时,就直接引用第一次导入模块时的那个名称空间。*
*模块的循环导入*
m1.py
#m1
print("from m1")
from m2 import y
x = "m1"
m2.py
#m2
print("from m2")
from m1 import x
y = "m2"
run.py
import m1
*执行run程序 导入m1,执行到 from m2 import y 会去导入 m2 并且寻找y的内存地址,但是导入m2之后,*
*又执行了from m1 import x,这时候又会去回到m1中找x的内存地址,但是x这时候还没有被放入内存中,就会发生锁一样的东西,*
*程序就会报错。*
如何来解决循环导入,并解决第1题中的循环导入问题
方法一:
把x="m1"放到 from m2 import y 上面,就等于先把x放入到内存里,这时候继续往下执行,执行到m2中的from m1 import x的时候,
程序就找到x的内存地址。锁就自然就开了。
方法二:
将from m2 import y定义在函数里面,先放到内存中,这时候就会自然向下执行x="m1",将from m1 import x也定义为函数,
将函数的内存地址也给导入到m1中,也就是from m2 import y,f2 并且执行f2()
在主程序run里面调用m1中的函数f1,这时候就不会发生锁了
区分python文件的两种用途
*#当文件被执行时__name__=='__main__' (执行文件)*
*#当文件被导入时__name__=='模块名' (被导入的模块)*
*当加入 if __name__=='__main__':的时候*
*在这条语句下面的方法调用,只会在执行此文件时才会被调用,在其他文件里是运行不了的。*
要分清大前提:什么是执行文件,什么是被导入文件
模块的搜索路径
模块搜索路径的优先级:
*1. 内存中已经加载过的*
*2. 内置模块*
*3. Sys.path(环境变量)中的 第一个值是当前执行文件所在的文件夹* (pychram会添加一条当前目录的父目录,放在第二个位置,帮助我们识别一些其他的路径,可以让我们写程序的时候,可以用TAB键补齐语法)
# 环境变量是以当前执行文件为准的
# 强调:所有被导入的模块参照环境变量sys.path都是以执行文件为准的
*注:命名模块时,不可与内置模块的名字冲突*(模块搜索路径,内置的优先级比sys.path的高)
*模块的绝对导入:以sys.path为基准寻找模块的方式*
* 优点:执行文件与被导入的模块都可以使用*
* 缺点:所有的被导入的模块,都是参照执行文件的sys.path,导入麻烦 *
*模块的相对导入:参照当前文件的文件夹为起始位置开始查找,称之为相对导入。*
*优点:导入更加简单*
* 缺点:只能在被导入的模块中使用,不能再执行文件中使用。(执行文件只能用绝对导入)*
* 符号:. 表示当前文件所在文件的文件夹。. . 表示前文件所在文件的文件夹的上一级。. . .表示上一级的上一级文件夹*
比如有A,B,C三个文件
在A中导入B,如果想在B中导入C,模块的搜索路径是以A为准的。A是执行文件,B,C是模块
环境变量是以当前执行文件为准的,所有的被导入的模块,参照的sys.path都是执行文件的。(sys.path是个列表,里面有多个值)
Import sys.
Sys.path.append(r”路径”)可添加sys.path。
*软件开发的目录规范*
*bin:放程序入口*
*conf:放配置文件*
*core:放业务逻辑的文件*
*db:放关于业务数据的文件*
*lib:放需要公共使用的包或模块*
*log:放日志文件*
*Readme:写关于软件的使用手册或一些介绍*
包的使用
1、在导入时带点的,点的左边必须是一个包,这是导入包特有的语法
2、包内,模块直接的导入应该使用from。。。import 。。。
3、from 。。。 import。。。,import后必须是一个明确的名字,没有任何的前缀
例如: from a.b.c.d.f import g.h.x #错误
1、f左边必须都是包
2、import后的名字不能有任何前缀
#模块名约定用全小写
#包内的模块没有右键运行的需求
2、格式化的字符串
print(time.strftime('%Y-%m-%d %H:%M:%S %p'))