疫情环境下的网络学习笔记 python 3.27-3.28
3.27
昨日回顾
-
算法:高效解决问题的方法
二分法+递归
-
在递归多层函数时,要考虑每一层返回的值
-
面向过程编程:一步步解决问题,优点:复杂问题简单化,缺点:扩展性差
-
匿名函数:lambda,临时使用的函数
lambda x,y:x+y
-
模块:一堆功能的集合体
内置,第三方:拿来就用
自定义:不同文件中共用的功能放进模块,减少代码冗余
-
导入模块发生的三件事
- 执行代码
- 产生名称空间
-
引用:模块名.功能名
今日内容
- 一个python文件有几种用途
- 执行python文件与导入python文件的区别
- import发生的事情
- from import
- 循环导入问题
- 苏索模块的路径与优先级
- 区分python文件的两种用途
- 编写一个规范的模块
- 包(重要)
- 软件开发的目录规范
正课
python文件的几种用途
- 被当作程序直接运行
- 当作模块被导入
导入模块时执行的三个步骤:
- 造一个模块的名称空间
- 开始执行模块的代码,运行中产生的名字放在名称空间内
- 在当前位置造一个名字:模块名,指向刚刚创建的名称空间
二者的区别:
导入的模块的名称空间在主程序运行完才会销毁
区分文件的用途:__name__
- 当foo.py被运行时,
__name__
的值为__main__
- 当foo.py 被当作模块被导入时,
__name__
的值为foo
用__name__
可以在不同应用场景下对文件执行不同的操作
if __name__ == '__main__':
foo.py被当做脚本执行时运行的代码
else:
foo.py被当做模块导入时运行的代码
from...import
普通地使用import...as...,每次使用模块的功能都需要 模块名.功能名
- 优点:指名道姓地操作模块名称空间中的名字,不会与当前名称空间中的名字冲突
- 缺点:加前缀麻烦
为了简洁,可以使用 from 模块名 import 功能名,直接使用模块中的功能名
from foo import x
from foo import get
from foo import change
print(x)
print(get)
使用from foo import..的三个步骤
- 产生一个模块的名称空间
- 运行foo.py,将运行过程中产生的名字都丢到模块的名称空间去
- 在当前名称空间拿到一个名字,该名字与模块名称空间中这个名字的内存地址绑定
from import优缺点
- 优点:不用加前缀,代码更精简
- 缺点:容易与当前名称空间混淆
一行可以用逗号分隔,导入多个名字
from foo import x,get,change
可以用 * 导入所有名字
from foo import *
# 导入所有名字,与import不同,不用加前缀,所以容易混淆
__all__
:在foo.py中用 __all__ = []
去控制*中得到的名字
循环导入
垃圾设计,但是我们要学会识别这种情况
被导入的模块 A 只会执行一次,如果在模块中导入别的模块 B 之后还有名字被定义,那么会先执行导入 B 模块的操作。如果B模块中又有导入A模块的操作,那么就不会再执行A模块了,而A模块中导入B模块下面的操作就不会执行,则报错
解决:将A中导入B的操作放到函数中,函数的定义阶段不会执行代码,就不会执行导入B的操作
模块的搜索路径优先级
模块本质上也是文件,无论是import还是from import,导入模块时都涉及到查找文件问题
查找的优先级:
-
内存(内置的模块)
-
从硬盘找:
-
按照sys.path中存放的文件的顺序依次查询要导入的模块
import sys print(sys.path) # 运行文件所在文件夹的环境变量,值为一个列表,存放一系列的文件夹 # 其中第一个文件夹是当前执行文件所在的文件夹 # 第二个文件夹是当前pycharm项目的文件夹,pycharm帮你加的文件夹 # 都找不到,则这种方法报错
-
可以通过sys中的方法可以看已经加载到内存中的模块
import sys
print(sys.modules)
# 环境变量是以执行文件为准的,所有的被导入的模块或者说后续的其他文件引用的sys.path都一样
python中有优化机制,因为申请模块的内存空间比申请变量的内存空间要大的多,所以python在程序运行中不会轻易回收模块的内存空间,del 模块名 都删除不了已经导入的模块
引用环境变量以外的模块
想要在sys.path以外别的地方放模块,可以这么做
import sys
sys.path.append(r'要添加的模块的绝对路径')
# 将要添加的文件夹加到环境变量中,那么在导入模块查找文件的时候就会找这个文件夹
import foo
编写模块应该遵循的规则
- 开头写模块的说明
- 尽量使用独立变量
补充函数的知识点
-
强类型 / 弱类型
变量的数据类型一旦被定义,就不可以被改变,除非进行转化:python是强类型的语言
-
动态型 / 静态型
-
python定义函数的时候在形参后面加冒号 数据类型可以对传入进行提示
def index(name:'传入str',age:'传入数字'): pass # 函数的提示可以通过__anotations__()查看 print(index.__annotations__())
包
什么是包
包就是一个包含有 __init__.py
文件的文件夹,包的本质是模块的一种形式
为何要包
包被当作模块导入
import bao
from bao import bun
# 和普通文件的模块用法一样
导入包,进行的三个步骤;
- 产生一个名称空间
- 运行包内的
__init__.py
文件,将运行过程中产生的名字都丢到 1 的名称空间去 - 在当前执行文件所在的名称空间中得到一个名字 bao,该名字指向
__init__.py
的名称空间,导入包时并不会导入包下所有的子模块与子包
强调:
- python3,包中没有
__init__.py
也没事,python2中会报错 - 创建包的目的不是为了运行,而是被导入使用的
包中导入模块
要导入包中的模块,有以下几个方法
-
绝对导入:以包的文件夹作为起始来进行导入,在
__init__.py
中导入模块#__init__.py # 包名.模块名 模块中的名字 from bao.m1 import f1 from bao.m2 import f2 from bao.m3 import f3 # bao文件夹下,m1模块中的f1 # bao文件夹下,m2模块中的f2 # ...
在使用包的时候,导入的环节和调用功能的方式一样
import bao bao.f1() # bao包中m1模块下的f1
导入包也可以用 from import语法,在执行程序的时候不用写前缀名:
# 执行主文件中 from bao import f1,f2,f3 f1() f2()
-
相对导入:仅限于包内使用,不能跨出包
# __init__.py # .代表当前文件夹 # .. 代表上一层文件夹 from .m1 import f1 # 当前文件夹下的m1的f1方法 from .aaa.m4 import f1 # 当前文件夹下aaa文件夹下的m4中的方法f1
强调: 在导入过程中带 .
的,点的左边必须是包,可以有一连串的点,表示一连串的包嵌套
from a.b.c.e import xxx
import a.b.c.e
# .的左边必须是包
# a,b,c,e都是包
导入之后就没有左边必须是包的这种限制了
两种导入模式的优缺点:
- 绝对导入
- 以顶级的包为起始,点的形式往下找子包,一定能找到
- 更改包名或着模块名的时候,导入的方式全部要改变
- 能够导入任意地方的包
- 相对导入
- 包内模块彼此之间的导入,推荐使用相对导入
- 当对包名更改时,因为只考虑在包内的相对位置,改的少
- 不能跨出包
导入包也可以用 *
软件开发的目录规范
- bin:存放程序中常用的自定义模块
- config:配置文件
- db:数据库相关的代码
- lib:library,库,每部分公用的功能
- core:核心代码的逻辑
- api:接口
- run:启动文件
- setup:安装,部署,打包的脚本
- requiments:存放软件依赖的外部数据
- readme:说明文档
import os
print(__file__)
# 显示当前机器当前文件的绝对路径
print(os.path.dirname())
# 显示当前机器当前文件所在的文件夹名
通过这种方式获取当前文件的文件夹名,将他append进环境变量,这样在程序的所有的代码中,都可以调用父级文件夹下的模块
if __name__ == '__main__'
src.run()