一、异常处理语法结构
1.异常处理语法结构
| 1.语法结构 |
| try: |
| 待监测的代码(可能会出错的代码) |
| except 错误类型 as e: |
| 针对上述错误类型制定的方案 |
| |
| |
| |
| 常见的异常: 1)语法错误:SyntaxError:invalid syntax |
| 2)名字错误:NameError |
| 3)索引错误:IndexError |
| 4)字典关键字错误:KeyError |
| 5)缩进错误:IndentationError |
| |
| 2.万能异常 |
| 如果不知道异常会是什么类型,则可以用万能异常Exception来代替 |
| |
| try: |
| 待监测的代码(可能会出错的代码) |
| except Exception as e: |
| |
| |
| 针对上述错误类型制定的方案 |
| |
| 3.try语句和 else语句 |
| else的子代码正常运行结束后没有任何报错后,才执行else子代码 |
| |
| try: |
| 待监测的代码(可能会出错的代码) |
| except Exception as e: |
| print(e) |
| 针对上述不同的错误类型统一处理 |
| else: |
| try的子代码正常运行结束没有任何报错后,再执行else子代码 |
| |
| 4. try语句和 finally语句 |
| finally语句:无论try的子代码是否报错,最后都要执行finally子代码 |
| |
| try: |
| 待监测的代码(可能会出错的代码) |
| except Exception as e: |
| print(e) |
| 针对上述不同的错误类型统一处理 |
| finally: |
| try的子代码是否报错都会执行 finally语句 |
2.异常处理的补充关键字 assert和raise
| 1.assert 断言 |
| assert 提前判断是否符合要求,是的话就继续往下走,不是的话就会报错 |
| 2.raise 主动抛异常 |
| 关键字 raise |
3.异常处理实战
| 使用while 循环+ 异常处理+迭代器对象,完成for循环迭代取值的功能 |
| |
| l1 = [11, 22, 33, 44, 55, 66, 77, 88, 99] |
| |
| |
| res = l1.__iter__() |
| |
| while True: |
| |
| try: |
| print(res.__next__()) |
| |
| except StopIteration as e: |
| break |
异常处理注意事项:
1.异常处理能尽量少用(try子代码监测会占用一定的资源)
2.被try监测的代码越少越好
3.当代码中可能会出现一些无法控制的情况报错 才应该考虑使用
二、生成器对象
1.什么是生成器对象
| |
| 1.本质 |
| 还是内置有__iter__和 __next__的迭代器对象 |
2.生成器函数
| 1. 生成器函数 |
| def my_iter(): |
| print('duoduodudoudouodo') |
| yield |
| |
| 2.生成器函数的作用 |
| |
| 1)函数体代码中加一个 yield关键字,那么函数名加括号并不会执行函数体代码,会生成一个生成器对象 |
| |
| my_iter() |
| res = my_iter() |
| |
| 2)使用加括号之后的就能够调用__next__才会执行函数体代码 |
| |
| res.__next__() |
| |
| 3)每次执行完__next__代码都会停在yield位置,下次基于该位置继续往下找第二个yield |
| |
| res.__next__() |
| |
3.用生成器对象实现range方法
| 自定义生成器对标range功能 |
| |
| |
| def my_range(start_num, end_num=None, step=1): |
| |
| if not end_num: |
| end_num = start_num |
| start_num = 0 |
| while start_num < end_num: |
| yield start_num |
| |
| start_num += step |
| |
| for i in my_range(1, 10, 2): |
| print(i) |
4.send()
方法给yield传参
| 通过调用send方法,将send的参数发送给 生成器,并且调用一次__next__方法,并把yield后的值返回给send函数 |
| |
| |
| def eat(name,age =None): |
| print(f'{name}的年龄未知') |
| while True: |
| food = yield |
| print(f'{name}的年龄是{age}') |
| res = eat('duo') |
| res.__next__() |
| res.send('123') |
5.生成器表达式
生成器里面的代码,执行的两种情况:
1 调用__next__方法
2 进行for循环
| 1.什么是生成器表达式:就是生成器的简化写法,结果是生成器对象。生成器表达式是一个能够将函数的灵活性与推导语法的简洁性结合到一起的工具 |
| |
| 2.生成器表达式的语句 |
| |
| |
| l1 = (i ** 2 for i in range(100)) |
| |
| print(l1) |
| |
| |
| for i in l1: |
| print(i) |
6.索引取值和迭代取值的差异
| 1.索引取值 |
| 优点:可以任意位置,任意次数取值 |
| 缺点:不支持无序类型的数据取值 |
| 2.迭代取值 |
| 优点:支持所有类型的数据取值(无序有序都可以迭代取值) |
| 缺点:只能从前往后依次取值,无法后退 |
三、模块
1.模块简介(本质、作用、表现形式、分类)
| 1.模块的本质 |
| 模块是 内部具有一定功能(代码)的py文件、文件夹 |
| |
| 2.模块的作用 |
| 1) 将出现代码和数据封装起来以便再利用 |
| 2) 同时提供那个自包含的命名空间避免程序出现变量名冲突(模块的全局作用域变成了模块对象的属性命名空间) |
| 3) 一个模块文件顶层定义的所有变量都变成了被导入的模块对象的属性,通过导入模块获得这个模块定义的工具的访问权,获得它的属性从而使用其中的工具 |
| |
| 3.模块的表现形式 |
| 1)py文件(py文件也可以称之为模块文件) |
| 2)含有多个py文件的文件夹(按照模块功能的不同划分不同的文件夹存储) |
| 3)已被编译为共享库或DLL的c或者C++扩展 |
| 4)使用C编写并链接到python解释器的内置模块 |
| |
| 4.模块的分类 |
| 1)自定义模块:程序员自己写的模块文件) |
| 2)内置模块:python解释器提供的模块 |
| 3)第三方模块:别人写的模块文件(大佬写的模块) |
2.导入模块的两种语句
强调:
- 一定要搞清楚谁是执行文件,谁是被导入文件
2. 以后开发项目的时候py文件名称一般是纯英文
3. 导入模块文件不需要填写后缀名
1 import句式
| 1.import句式 |
| 使导入者以一个整体获取一个模块,我们获取模块中的名称时,必须通过模块名点号来获取该模块的属性 |
| |
| 2.import 句式执行时,发生的事情: |
| 1 先产生执行文件的名称空间 |
| 2 执行被导入文件的代码将产生的名字放入被导入文件的名称空间中 |
| 3 在执行文件的名称空间中产生一个模块的名字 |
| 4 在执行文件中使用该模块名 点(dot nonation)的方式使用模块名称空间中所有的名字 |
2 from... import 句式
| 1.from... import 句式 |
| 直接点明要导入的模块中的变量名,允许导入者从一个模块文件中获取(复制)特定的名称,from语句可以让我们直接在脚本中使用复制后的名称,不需要通过模块+点的方式 |
| |
| 2.from... import... 句式执行时,发生的事情: |
| 1 先产生执行文件的名称空间 |
| 2 执行被导入文件的代码将产生的名字放入被导入文件的名称空间中 |
| 3 在执行文件的名称空间中产生对应的名字绑定模块名称空间中对应的名字 |
| 4 在执行文件中直接使用名字就可以访问名称空间中对应的名字 |
import与 from... import... 句式 两者的优缺点
1) import句式:
优点:不会发生名字冲突
由于使用模块名称空间中的名字都需要模块名点的方式才可以用,所以不会轻易的被执行文件中的名字替换掉
劣势:繁琐一点,每次使用模块名称空间的名字都必须使用模块名点才可以
2) from... import
优点:简便
指名道姓的导入模块名称空间中需要使用的名字,不需要模块名点
劣势:会发生名字冲突
3.导入模块语句的补充说明
| 1.重复导入模块:解释器只会导入一次,后续重复导入语句并不会执行 |
| |
| 2.用 as关键字起别名,简化模块名 |
| 模块名很长可以用 as语句来起别名,为变量名较长的变量提供简短的别名 |
| |
| |
| import duoduoduoaaaaaa as da |
| from jdfasdfa import jaaaddefd as j |
| from a import name as n, func1 as f1 |
| |
| 3.涉及到多个模块导入的语句 |
| 一般导入的模块的功能相似时候,用逗号隔开的方式,如果相似度不高可以使用多个import来导入不同的模块 |
| |
| 1)模块功能不相似时,多个语句单独导入 |
| |
| import a |
| import jigeerciyuan |
| |
| 2)模块功能相似时,单个语句一起导入,名字用逗号隔开 |
| |
| import a, jigeerciyuan |
5.使用__name__
属性判断文件类型
| 1.__name__内置属性简介 |
| 模块即可以当作模块文件导入,也可以当作独立的程序运行,而每个模块都有一个名为__name__的内置属性,可以用来判断文件的类型 |
| |
| 1)当py文件是执行文件(顶层文件)的时候, |
| 启动__name__就会被设置为字符串"__main__" |
| 2)当py文件是被导入文件的时候,启动__name__对应的就是模块名 |
| |
| if __name__ == '__main__': |
| print('我是执行文件,我可以运行这里的子代码') |
| |
| 上述脚本可以用来区分所在py文件内python代码的执行,__name__变量充当了一饿使用模式标准符 |
| |
| |
6.__all__
与from ... import *
语句
| 1.from ... import * 语句 |
| 功能:from a import * *默认是将模块名称空间中所有的名字导入(或取得模块顶层被复制的所有名称的副本) |
| |
| 2. __all__ 和 from a import * 搭配使用 |
| |
| __all__ = ['名字1', '名字2'] 可以改变全部导入名字,指定导入的名字 |
7.模块的查找顺序
| 1.内存 |
| 使用了关键字 import或者 from 导入的时候内存可以临时储存,这时候删掉不会报错,运行之后内存释放再运行则找不到要导入的模块报错 |
| |
| 2.内置 |
| 1)当自定义模块和内置模块冲突,内置模块优先级更高 |
| 2)命名模块名时,不要和内置模块冲突 |
| |
| 3.执行文件所在的环境变量 sys.path(系统环境变量) |
| 我们可以将模块所在的路径也添加到执行文件的sys.path中,从而去查找模块 |
8.绝对导入和相对导入
相对导入使用频率低,一般用绝对导入即可,结构更加清晰
| 1.绝对导入 |
| 站在执行文件的角度导入,按照项目的根目录为准导入 |
| |
| |
| from mymd import ccc |
| from mymd.aaa.bbb.ccc import ddd |
| print(ccc.name) |
| |
| 2.相对导入 |
| 不依据执行文件所在的sys.path 而是以模块自身路径为准 |
| |
| .在路径中表示当前目录 |
| ..在路径中表示上一层目录 |
| ..\..在路径中表示上上一层目录 |
| |
9.导入包的具体使用
1 一个包中的模块,在功能上应该是相似的
2 为了兼容性考虑,包中最好还是有__init__.py
文件,因为导入包的实质就是导入包的__init__.py
文件
| 1.如果只想用包中的某几个模块,那么还是按照之前的导入方式即可 |
| from aaa import md1, md2 |
| |
| 2.如果直接导入包名其实就是导包下面的__init__.py文件,该文件内有什么名字就可以通过包名点什么名字 |
| |
| 3.导入包时,名称空间的变化 |
| |
| 1)执行包下面的__init__.py文件 |
| 2)产生一个新的名称空间用于存放__init__.py执行过程中产生的名字 |
| 3)在当前执行文件所在的名称空间中得到一个名字 aaaaa,该名字指向__init__.py的名称空间 |
| |
| |
四、软件开发目录
目录规范主要规定开发程序的过程中针对不同的文件功能做不同的分类,为了提高程序的可读性和可维护性
| 1.bin文件夹(主要存放项目的启动文件) |
| start.py |
| |
| |
| 2. conf文件夹(主要存放项目的配置文件(设置的选项)) |
| settings.py |
| |
| 3.core文件夹(主要存放项目核心文件) |
| src.py |
| |
| 4.interface文件夹(主要存放项目接口文件) |
| goods.py |
| user.py |
| |
| |
| 5.db文件夹(主要存放项目相关的数据) |
| userinfo.txt |
| dbhandler.py |
| |
| |
| 6.log文件夹(日志文件:记录信息 主要存放项目日志文件) |
| log.log(也可以根据日志类型分的更加细致) |
| |
| 7.lib文件夹(主要存放项目公共功能) |
| common.py |
| |
| 8.README文件(项目相关的说明文件) |
| |
| 9.requirements.txt(主要存放项目所需模块及版本) |
五、python常用内置模块
1.collections
模块
模块名称 |
作用 |
namedtuple具名元组 |
namedtuple是一个函数,它用来创建一个自定义的tuple对象,并且规定了tuple元素的个数,并可以用属性而不是索引来引用tuple的某个元素 |
deque双端队列 |
为了高效实现插入和删除操作的双向链表结构,非常适合实现队列和堆栈这样的数据结构 |
OrderedDict有序字典 |
OrderedDict的key会按照插入的顺序排列,不是key本身排序 |
Counter计数器 |
统计元素出现的个数 |
1 具名元组 namedtuple
| 1.语法: namedtuple('名称',[属性list]) |
| namedtuple是一个函数,它用来创建一个自定义的tuple对象,并且规定了tuple元素的个数,并可以用属性而不是索引来引用tuple的某个元素 |
| |
| 2.用namedtuple构建一个表示圆的函数 |
| |
| |
| from collections import namedtuple |
| circle = namedtuple('圆Circle', ['x', 'y', 'r']) |
| c1 = circle(3, 5, 7) |
| print(c1) |
| print(c1.x) |
| print(c1.y) |
| print(c1.r) |
2 双端队列 deque
队列与堆栈
队列:先进先出
堆栈:先进后出
队列和堆栈都是一边只能进一边只能出
-
deque
对于数据的处理
.pop() 方法和 .popleft()方法
| |
| |
| from collections import deque |
| q = deque([3, 2, 1]) |
| print(q) |
| print(q.pop()) |
| print(q.popleft()) |
3 有序字典 OrderedDict
特点:按照插入的key的顺序,进行有序排列
- 有序字典 OrderedDict
| |
| from collections import OrderedDict |
| |
| od = OrderedDict([('a', 1), ('b', 2), ('c', 3)]) |
| print(od) |
| print(od.get('a')) |
| print(od.values()) |
- 小练习
| 将大于60的值保存在字典的k1中,小于60的保存在k2中,{'k1': 大于60 , 'k2': 小于60} |
| l1 = [11, 22, 33, 44, 55, 66, 77, 88, 99] |
| |
| 1.for 循环 |
| |
| d1 = {'k1': [], 'k2': []} |
| for i in l1: |
| if i < 60: |
| d1['k1'].append(i) |
| else: |
| d1['k2'].append(i) |
| print(d1) |
| |
| 2.列表推导式 |
| |
| d1 ={ |
| 'k1':[i for i in l1 if i <60], |
| 'k2':[i for i in l1 if i >60] |
| } |
| print(d1) |
| |
| 3.filter函数 |
| |
| d2 = { |
| 'k1': list(filter(lambda x: x < 60, l1)), |
| 'k2': list(filter(lambda x: x > 60, l1)) |
| } |
| print(d2) |
4 统计Counter
作用:跟踪值出现的次数,生成一个无序的容器类型,以字典的键值对形式存储结果,其中元素为key,计数结果为value
| |
| from collections import Counter |
| |
| s1 = 'aaabbb' |
| print(Counter(s1)) |
2 .time
时间 模块
在python中时间的表现形式有三种:
- 时间戳(
timestamp
) :通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。
- 结构化的时间(
struct_time
): struct_time元组中共有九个元素
- 格式化的时间字符串 (
Format String
)
索引(Index) |
属性(Attribute) |
值(Values) |
0 |
tm_year(年) |
2022 |
1 |
tm_mon(月) |
1 - 12 |
2 |
tm_mday(日) |
1 - 31 |
3 |
tm_hour(时) |
0 - 23 |
4 |
tm_min(分) |
0 - 59 |
5 |
tm_sec(秒) |
0 - 60 |
6 |
tm_wday(weekday) |
0 - 6(0表示周一) |
7 |
tm_yday(第几天) |
1 - 366 |
8 |
tm_isdst(是否是夏令时) |
默认为0 |
1.time模块内容
模块名称 |
用法 |
time.localtime |
将一个时间戳时间转换成当前时区的struct_time |
time.gmtime |
是将一个时间转成格林尼治时间 |
time.strftime |
把一个代表时间的元组或者结构化时间转换为格式化时间字符串%Y/%m/%d %H:%M:%S |
time.time |
返回当前时间的时间戳 |
time.sleep |
让程序原地阻塞指定的秒数 |
| 1.print(time.localtime()) |
| |
| |
| 2.print(time.gmtime()) |
| |
| |
| 3.print(time.strftime('%Y/%m/%d %H:%M:%S')) |
| |
| |
| 4.print(time.time()) |
| |
| |
| 5.time.sleep(10) |
3.datetime
时间模块
模块名称 |
作用 |
date |
日期对象,常用的属性有year, month, day |
time |
时间对象 |
datetime |
日期时间对象,常用的属性有hour, minute, second, microsecond |
timedelta |
时间间隔,即两个时间点之间的长度 |
fromtimestamp |
转换时间戳 |
| 1.print(datetime.datetime.now()) |
| |
| 2.print(datetime.date.today()) |
| |
| 3.print(datetime.utcnow()) |
| |
| 4. |
| c = datetime.datetime(2017, 5, 23, 12, 20) |
| print('指定日期:',c) |
| |
| |
| 5.timedelta 设定时间间隔 |
| import datetime |
| ctime = datetime.date.today() |
| print(ctime) |
| time_del = datetime.timedelta(days=3) |
| print(ctime + time_del) |
4.random
随机数模块
模块名 |
作用 |
random.random() |
0,1之间时间生成的浮点数 float |
random.randint(1,10) |
产生 1 到 10 的一个整数型随机数 ,包含10 |
random.choice() |
从序列中随机选取一个元素 |
random.choices() |
从序列中随机选取一个元素,保留其数据类型 |
random.randrange(1,100,2) |
生成从1到100的间隔为2的随机整数,不包括100 |
random.sample(population, k) |
在总体序列population中随机抽取k长度的列表 |
random.shuffle() |
随机打乱数据集 |
| 1.print(random.randint(1, 6)) |
| 2.print(random.randrange(1, 100, 2)) |
| 3.print(random.choice(['1等奖', '2等奖', '3等奖', '谢谢惠顾'])) |
| print(random.choices(['1等奖', '2等奖', '3等奖', '谢谢惠顾'])) |
| 4.rint(random.sample(['jason',['a',1,'duo'], (10,9), {4,5,6}, 2], 2)) |
5.os模块
块名 |
作用 |
os.mkdir(`/os.makedirs() |
可以创建单级目录/多级目录 |
os.rmdir() / os.removedirs() |
可以删除单级目录/多级目录 |
os.listdir() |
列举内容名称 |
os.rename() |
重命名文件 |
os.remove() |
删除文件 |
os.getcwd() |
获取当前工作目录 |
os.chdir() |
切换当前工作目录 |
os.path.abspath(__file__) |
获取执行文件的绝对路径 |
os.path.dirname(__file__) |
获取执行文件所在的目录路径 |
os.path.exists() |
判断文件路径是否存在 |
os.path.isfile() |
判断文件是否存在 |
os.path.isdir() |
判断路径是否有该目录 |
os.path.getsize() |
获取文件大小 以字节为单位 |
| 1.os.rmdir(r'd1') |
| 2.os.removedirs(r'd2\d22\d222\d2222') |
| 3.print(os.listdir(r'/Users')) |
| |
| |
| 4.os.rename(r'a.txt'.r'aaa.txt') |
| 5.os.remove(r'aaa.txt') |
| 6.print(os.getcwd()) |
| |
| 7.os.chdir('..') |
| 8.s.mkdir(r'a.txt') |
| 9.os.path.abspath(__file__) 获取执行文件的绝对路径 |
| 10.os.path.dirname(__file__) 获取执行文件所在的目录路径 |
| 11.print(os.path.exists(r'bbb.txt')) |
| 12.print(os.path.exists(r'/Users/duoduo/pythonProject/python基础/day 10.20')) |
| 13.print(os.path.exists(r'/Users/duoduo/pythonProject/python基础/day 10.20')) |
| 14.print(os.path.isfile(r'/Users/duoduo/pythonProject/python基础/day 10.19')) |
| 15.print(os.path.isdir(r'/Users/duoduo/pythonProject/python基础/day 10.20/json 实战.py')) |
| 16.print(os.path.isdir(r'/Users/duoduo/pythonProject/python基础/day 10.19')) |
| 17.print(os.path.join(s1, s2)) |
6.sys模块
语句 |
功能 |
sys.path |
获取系统环境变量 |
sys.getrecursionlimit() |
获取解释器最大递归深度 |
sys.setrecursionlimit() |
更改解释器最大递归深度 |
sys.version |
获取解释器版本号 |
sys.platform |
平台信息 |
sys.argv |
从文件外部得到参数 |
| 1.sys.path 获取执行文件的 sys.path 系统环境变量 |
| 2.print(sys.getrecursionlimit()) |
| 3.print(sys.getrecursionlimit()) |
| 4.sys.version |
| 5.sys.platform |
| 6.res = sys.argv 命令行参数List,第一个元素是程序本身路径 |
7.json模块
语句 |
功能 |
json.dumps(python数据) |
序列化 |
json.dump(python数据,文件) |
序列化并存入文件 |
json.loads(json格式数据) |
反序列化 |
json.load(f) |
读出文件并反序列化 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY