目录
- 异常处理
- 生成器
- 索引取值与迭代取值的差异
- 包的具体使用
- 编程思想的转变
- 软件开发目录规范
- 模块
内容详细
异常处理
异常常见类型
SyntaxError # 语法错误;
NameError # 命名错误
IndexError # 索引错误
KeyError # 元素不存在
IndentationError # 缩进错误
异常处理语法结构
1.基本语法结构
try:可能错误的代码需要监测
except NameError:命名错误类型
针对上述错误类型制定的方案
2.查看错误信息
try: # 可能错误的代码需要监测
except NameError as e: # e系统提示的错误信息
针对上述错误类型制定方案
3.针对不同错误类型制定不同的解决方案
try: # 可能错误的代码需要监测
except IndexError as e: # e系统提示的错误信息
针对上述错误类型制定方案
try: # 可能错误的代码需要监测
except NameError as e: # e系统提示的错误信息
针对上述错误类型制定方案
try: # 可能错误的代码需要监测
except SyntaxError as e: # e系统提示的错误信息
针对上述错误类型制定方案
4.万能异常——Exception/baseException
Try: # 可能错误的代码需要监测
except Exception as e: # e就是系统提示的错误信息
针对各种常见的错误类型全部同意处理
5.结合else使用
Try: # 可能错误的代码需要监测
except EXception as e: # e就是系统提示的错误信息
针对各种常见的错误类型全部同意处理
else: # 所有的try子代码处理错误结束才能运行else子代码
6.结合finally使用
Try: # 可能错误的代码需要监测
except Exception as e: # e就是系统提示的错误信息
针对各种常见的错误类型全部同意处理
else: # 所有Try子代码处理错误结束才能运行else子代码
finally: # 不论try子代码是否报错,最后都要执行finally子代码
异常处理补充
1.断言:预言家提前判断,assert
name = 'jason'
assert isinstance(name,str)
print('哈哈 我就说肯定是字符串')
name.strip()
2.主动抛异常:raise
name = 'jason'
if name == 'jason':
raise Exception('老子不干了')
else:
print('正常走')
异常处理实战应用
1.异常处理能少用就尽量少用
2.被try监测的代码也是能少用就少用
3.当代码中可能会出现一些无法控制的报错情况才能考虑使用
eg:使用手机访问网络软件 突然断网
编写网络爬虫程序要求数据 断网
课堂练习:
使用while循环+异常处理+迭代对象,完成for循环迭代取值功能。
l1 = [11, 22, 33, 44]
# 1.先将列表调用__iter__转变成迭代器对象
iter_l1 = l1.__iter__()
# 2. while循环迭代器对象反复执行__next__
while True:
try:
print(iter_l1.__next__()) # 重复取出列表数值 __nexr__不会主动停止取值
except StopIteration as e: # 报错:去完后取不到值了报错
break # 所有我们主动加个结束
生成器
生成器对象
1.本质
还是内置有__iter__和__next__的迭代对象
2.区别
迭代器对象是解释器自动提供
数据类型/文件对象>>>迭代器对象
生成器对象是程序员编写出来的
代码、关键字>>>:迭代器对象(生成器)
3.创建生成器的基本语法
函数体代码中填写yield关键字
def my_iter():
print('哈哈 椰子汁好喝')
yield
# my_iter() # 不会执行函数体代码
1.函数替代吗中如果有yield关键字,那么函数名加括号不会执行函数体代码。会生成一个生成器对象(迭代器对象)
res = my_iter()
# print(res) # 执行函数体代码
2.使用加括号之后的结果调用__next__才会执行函数体代码
res.__next__()
3.每次执行完__next__代码都会听再yiedeld位置、下次基于该位置继续往下查找第二个yield
4.yield还有点类似于return,可以返回返回值
4.代码实现
def my_iter():
print('哈哈 椰汁不错')
yield 11
print('呵呵 一般')
yield 22
print('咋滴吧')
yield 33
res = my_iter()
r1 = res.__next__()
print(r1)
# 哈哈 椰汁不错
# 11
r2 = res.__next__()
print(r2)
# 哈哈 椰汁不错
# 11
r3 = res.__next__()
print(r3)
# 咋滴吧
# 33
yield冷门用法
def eat(name, food=None):
print(f'{name}准备用餐')
while True:
food = yield
print(f'{name}正在吃{food}')
res = eat('jason')
res.__next__()
res.send('汉堡') # 1.将括号内的数据传给yield前面的变量名
res.send('包子') # 2.再自动调用__next__
res.send('面条')
练习
自定义生成器对标range功能(一个参数、两个参数、三个参数、迭代器对象)
for i in range(1, 10):
print(i)
def my_range(start_num, end_num=None, step=1):
# 判断end_num是否有值,没有值说明用户只给了一个值,起始数字是0.终止位置应该是传的值
if not end_num:
end_num = start_num
start_num = 0 # 定义起始数字是0
while start_num < end_num:
yield start_num
start_num += step
for i in my_range(3):
print(i)
for i in my_range(1, 10):
print(i)
for i in my_range(1, 10, 2):
print(i)
生成器表达式
生成器的简化写法
# l1 = [i **2 for i in range(100)]
# print(11)
l1 = (i + 2 for i in range(1, 10, 2))
print(l1)
for i in l1:
print(i)
面试题
def add(n, i): # 普通函数 返回两个数的和 求和函数
return n + i
def test(): # 生成器
for i in range(4):
yield i
g = test() # 激活生成器
for n in [1, 10]:
g = (add(n, i) for i in g)
"""
第一次for循环
g = (add(n, i) for i in g)
第二次for循环
g = (add(10, i) for i in (add(10, i) for i in g))
"""
res = list(g)
print(res)
#A. res=[10,11,12,13]
#B. res=[11,12,13,14]
#C. res=[20,21,22,23]
#D. res=[21,22,23,24]
索引取值与迭代取值的差异
l1 = [11,22,33,44,55]
1.索引取值
可以任意位置任意次数取值
不支持无序类型的数据取值
2.迭代取值
只能从前往后依次取值无法后退
支持所有类型的数据取值(无序有序)
PS:两者的使用需要结合实际应用场景
包的具体使用
虽然python3对包的要求降低了,不需要_init_.py也可以识别。但是为了兼容性考虑最好还是家伙是那个_init_.py
如果只想用包中某几个模块,那么还是按照之前的导入方式即可
from aaa import md1,md2
如果直接导入包名
import aaa
导入包名下面的_init_.py,该文件有什么名字就可以通过包名点什么名字
编程思想的转变
1.面条版阶段
所有的代码全部堆叠在一起
2.函数版阶段
根据功能的不同封装不同的函数
3.模块阶段
根据功能的不同拆分不同的py文件
**
1.第一个阶段可以看成是直将所有的数据放在C盘
| 视频、音频、文本、图片 |
2.第二阶段可以看成是将C盘下的数据风雷管理
| 视频文件夹、音频文件夹、文本文件夹、图片文件夹
3.第三阶段可以看成是将C盘下的数据功能的不同划分到更合适的位置
| 系统文件夹 C盘 |
| 视频文件夹 D盘 |
| 图片文件夹 E盘 |
| ps:类似于开公司(小作坊、小公司、上市公司) |
| 为了资源的高效管理 |
软件开发目录规范
1.文件及目录的名字可以变换,但是思想是不变的分类管理
2.目录规范主要规定开发程序的过程中针对不同的文件功能需要做不同的分类
myproject项目文件夹
1. bin文件夹:存放项目启动文件
start.py:启动文件可以放在bin目录里能直接再项目根目录
2.conf文件夹:项目配置文件
settings.py:项目默认配置,一般都是大写
3.core文件夹:项目核心文件
src.py项目核心功能
4.interface文件夹:项目接口文件
goods.py:根据具体业务逻辑划分对应文件
user.py
account.py
5.db:项目相关数据
userinfp.txt
db_handler.py:数据库操作相关代码
6.log文件夹:项目日志文件
log.log
7.lib文件夹:公共功能
common.py
8.readme文件:说明书
9.requirements.txt文件:项目所需模块和版本
模块
模块简介
- 模块的本质
内部具有一定的功能(代码)的py文件 - python模块的历史
python刚开始的时候所有搞其他编程语言的程序员都看不起,甚至给python起了个外号>>>:调包侠(贬义词)
随着实际的发展项目的复杂程度越来越高,上面那帮人也不得不用python,然后发现了真香定律>>>:调包侠(褒义词) - python模块的表现形式
- py文件(py文件也可以称之为是模块文件)
- 含有多个py文件的文件夹(按照模块功能的不同划分不同的文件夹存储)
- 已被编译为共享库或者DLL的c或者C++扩展(了解)
- 使用C编写并链接到python解释器的内置模块(了解)
模块分类
- 自定义模块
我们自己写的模块文件 - 内置模块
python解释器提供的模块 - 第三方模块
别人写的模块文件(python背后真正的大佬)
导入模块的两种句式
- 强调:
- 一定要搞清楚谁是执行文件,谁是被导入文件
- 以后开发项目的时候py文件的名称一般是纯英文
- 不会含有中文甚至空格
- 01 作业讲解.py(不会出现)
- test.py/views.py(出现)
- 导入模块文件不需要填写后缀名
- import句式
- 以import a为例研究底层原理
1.1 先产生执行文件的名称空间
1.2 执行被导入文件的代码将产生的名字放入被导入文件的名称空间中
1.3 在执行文件的名称空间中产生一个模块的名字
1.4 在执行文件中使用该模块点名的方式使用模块名称空间中所有的名字
- 以import a为例研究底层原理
- from...import...句式
- 以from a import name,func1为例研究底层原理
1.1 先产生执行文件的名称空间
1.2 执行被导入文件的代码将产生的名字放入被导入文件的名称空间中
1.3 在执行文件的名称空间中产生对应的名字绑定模块名称空间中对应的名字
1.4 在执行文件中直接使用名字就可以访问名称空间中对应的名字
- 以from a import name,func1为例研究底层原理
导入模块补充说明
- import与from...import...两者优缺点
- import句式
- 由于使用模块名称空间中的名字都需要模块名点的方式才可以用所以一不会轻易的被执行文件中的名字替换掉,但由于每次使用模块名称空间中的名字都必须使用模块名点才可以。
- from...import...句式
- 指名道姓的导入模块空间中需要使用的名字,不需要模块名点。但是容易跟着执行文件中名字冲突。
- import句式
- 重复导入模块
- 解释器只会导入一次,后续重复的导入语句并不会执行
- 起别名
- import wuyongerciyuan as wy
- from wuyongerciyuan import zhanglovewu as zz
- form a import name as n,func1 as f1
- 涉及到多个模块导入
- import a
- import wuyongerciyuan
- 如果模块功能相似度不高,推荐使用第一一种。相似度高可以使用第二种
- import a, wuyongerciyuan
循环导入问题
- 循环导入
- 两个文件直接彼此并且相互使用各自名称空间中的名字,贼容易报错
- 如何解决循环导入问题
- 确保名字在使用之前就已经准备完毕
- 我们以后在编写代码的过程中应该尽可能避免出现循环导入
判断文件类型
所有的py文件都可以直接打印_name_对应的值
当py文件是执行文件的时候_name_对应的值是_main_
当py文件是被带入文件的时候_name_对应的值是模块名
if _name_ == '_main_':
print('haha,我是执行文件可以运行这里的子代码')
上面脚本可以用来区分所在py文件内oython代码执行
使用场景
模块开发阶段
项目启动文件
'''
from a import * *默认是将模块名称空间中所有的名字导入
_all_ =['名字', '名字1'] 针对*可以限制拿的名字
'''
模块的查找顺序
1.内存
imprt aaa
import time
time.sleep
print(aaa.name)
aaa.func1()
2.内置
import time
print(time)
print(time.name)
'''
以后在自定义模块的时候尽量不要与内置模块冲突
'''
3.执行文件所在的sys.path(系统环境环境)
一定要以执行文件为准!!!
我们可以将模块所在的路径也提取到执行文件的sys.path中即可
import sys
print(sys.path) # 列表
sys.path.append(r'D:\pythonProject03\day17\mymd')
import ccc
print(ccc.name
绝对导入与相对导入
"""
再次强调:一定要分清楚谁说执行文件!!!
模块的导入全部以执行文件为准
"""
绝对导入
from mymd.aaa.bbb.ccc.ddd import name # 可以精确到变量名
from mymd.aaa.bbb.ccc import ddd # 也可以精确到模块名
ps:套路就是按照项目根目录一层层往下查找
相对导入
.在路径中表示当前目录
..在路径中表示上一层目录
..\..在路径中表示上上一层目录
不在一句执行文件所在的sys.path,而是以模块自身路径为准
from. import b
相对导入只能用于模块文件中,不能再执行文件中使用
"""
相对导入使用频率较低,一般用绝对导入即可。结构更加清晰
"""
常用内置模块之collections模块
1.具名元组:namedtuple
from collections import namedtuple
表示二位坐标系
point = namedtuple('点',['x','y'])
生成点信息
p1 = point(1, 2)
print(p1) # 点(x=1, y=2)
print(p1.x) # 1
print(p1.y) # 2
card = namedtuple('扑克牌', ['num', 'color'])
c1 = card('A', '黑♠')
c2 = card('A', '红♥')
print(c1, c1.num, c1.color)
print(c2, c2.num, c2.color)
2.队列
队列与堆栈
队列:先进先出
堆栈:先进后出
队列和堆栈都是一边只能进一边只能出
常用内置模块之时间模块
import time
"""
三种时间表现形式
1.时间戳:指的是从19701月1日零时零分零秒至现在时间的总秒数,在计算机领域去计算时间差的时候一般都会先转为时间戳再进行计算。
秒数
2.结构化时间
主要是给计算机看的 人看不适应
3.格式化时间
主要是给人看的
"""
# print(time.time()) # 1666150097.5481427
# print(time.localtime()) # time.struct_time(tm_year=2022, tm_mon=10, tm_mday=19, tm_hour=11, tm_min=32, tm_sec=50, tm_wday=2, tm_yday=292, tm_isdst=0)
# print(time.strftime('%Y-%m-%d')) # 2022-10-19
# print(time.strftime('%Y/%m/%d')) # 2022/10/19
# print(time.strftime('%Y/%m/%d %H:%M:%S')) # 2022/10/19 11:30:20
# print(time.strftime('%Y/%m/%d %X')) # 2022/10/19 11:31:18
time.sleep(10) # 让程序原地阻塞指定的秒数
# import datetime
# print(datetime.datetime.now()) # 2022-10-19 11:58:23.682282
# print(datetime.datetime.today()) # 2022-10-19 11:58:23.682282
# print(datetime.date.today()) # 2022-10-19
'''
datetime 年月日 时分秒
date 年月日
time 时分秒(后续会有此规律)
'''
# from datetime import date, datetime
# print(date.today())
# print(datetime.today())
# print(datetime.utcnow())
# import datetime
# c = datetime.datetime(2017, 5, 23, 12, 20)
# print('指定日期:',c) # 指定日期: 2017-05-23 12:20:00
from datetime import datetime
# d=datetime.strptime('2017/9/30','%Y/%m/%d')
# print(d) # 2017-09-30 00:00:00
# e=datetime.strptime('2017年9月30日星期六','%Y年%m月%d日星期六')
# print(e)
# f=datetime.strptime('2017年9月30日星期六8时42分24秒','%Y年%m月%d日星期六%H时%M分%S秒')
# print(f)
import datetime
# ctime = datetime.date.today()
# print(ctime)
# time_del = datetime.timedelta(days=3)
# print(ctime + time_del)
# ctime = datetime.datetime.today()
# print(ctime)
# time_del = datetime.timedelta(minutes=20)
# print(ctime + time_del)
常用内置模块之随机数模块
import random
# print(random.random()) # 随机产生0到1之间的小数
# print(random.randint(1, 6)) # 随机产生1到6之间的整数
# print(random.randrange(1, 100, 2)) # 随机产生指定的整数
# print(random.choice(['一等奖', '二等奖', '三等奖', '谢谢惠顾'])) # 随机抽取一个样本 '二等奖'
# print(random.choices(['一等奖', '二等奖', '三等奖', '谢谢惠顾'])) # 随机抽取一个样本 ['二等奖']
# print(random.sample(['jason', 'kevin', 'tony', 'oscar', 'jerry', 'tom'], 2)) # 随机抽指定样本数 ['tom', 'jerry']
# l1 = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 'A']
# random.shuffle(l1) # 随机打乱数据集
# print(l1)
'''产生图片验证码: 每一位都可以是大写字母 小写字母 数字 4位'''
def get_code(n):
code = ''
for i in range(n):
# 1.先产生随机的大写字母 小写字母 数字
random_upper = chr(random.randint(65, 90))
random_lower = chr(random.randint(97, 122))
random_int = str(random.randint(0, 9))
# 2.随机三选一
temp = random.choice([random_upper, random_lower, random_int])
code += temp
return code
res = get_code(10)
print(res)
res = get_code(4)
print(res)
os模块
os模块主要与代码运行所在的操作系统打交道
import os
1.创建目录(文件夹)
os.mkdir(r'd1') # 相对路径 在执行文件所在的路径下创建目录——可以创建单机目录
os.mkdir(r'd2\d22\d222') # 不可以创建多级目录
os.makedirs(r'd2\d22\d222') # 可以创建多级目录
os.makedirs(r'd3') # 可以创建单级目录
2.删除目录(文件夹)
os.rmdir(r'd1') # 可以删除单级目录
os.rmdir(r'd2\d22\d222') # 不可以一次性删除多级目录
os.removedirs(r'd2\d22') # 可以删除多级目录
os.removedirs(r'd2\d22\d222\d2222') # 只能删除空的多级目录
os.rmdir(r'd3') # 只能删空的单级目录
3.列举指定路径下内容名称
print(os.listdir()) # 找到当前路径下文件夹内容名称
print(os.listdir('D:\\')) # 找到指定路径下所有文件内容名称
4.删除/重命名文件
os.rename(r'a.txt', r'aaa.txt') # 找到指定路径文本重命名
os.remove(r'aaa.txt') # 删除指定路径文本
5.获取/切换当前工作目录
# print(os.getcwd()) # D:\pythonProject2\10-20
# os.chdir('..') # 切换到上级目录
# print(os.getcwd())
# os.mkdir(r'hei') # 创建‘hei’文件夹
6.动态获取项目根路径(重要)
print(os.path.abspath(__file__)) # 获取执行文件的绝对路径 D:\pythonProject2\10-20\os模块.py
print(os.path.dirname(__file__)) # 获取执行文件所在的文件夹 D:/pythonProject2/10-20
7.判断路径是否存在(文件、目录)
print(os.path.exists(r' os模块.py')) # True 判断文件路径是否存在
print(os.path.exists(r'D:\pythonProject2\10-20')) # True 判断目录是否存在
print(os.path.isfile(r' os模块.py')) # True 判断路径是否是文件
print(os.path.isfile(r'D:\pythonProject2\10-20\ os模块.py')) # 判断路径是否是文件 False
print(os.path.isdir(r' os模块.py')) # False
print(os.path.isdir(r'D:\pythonProject2\10-20')) # True
8.路径拼接(重要)
s1 = r'D:pythonProject2\10-20'
s2 = r'os模块.py'
print(f'{s1}\{s2}') # D:pythonProject2\10-20\os模块.py
print(os.path.join(s1, s2)) # D:pythonProject2\10-20\os模块.py
9.获取文件大小(字节)
print(os.path.getsize(r'a.txt')) # 0
sys模块
import sys
print(sys.path) # 当前所在文件执行的环境变量——py-charm自动添加了一个
print(sys.getrecursionlimit()) # 获取python解释器默认最大递归深度
sys.setrecursionlimit(2000) # 修改python默认最大递归深度
print(sys.version) # 获取 版本号及版本日期
print(sys.platform) # 平台信息 win32
res = sys.argv # 后面可以添加条件
if len(res) != 3: # 如果列表里res不等于3
print('执行命令缺少了用户或密码')
else: # 否则
username = res[1] # 名字等于索引列表1
password = res[2] # 密码等于索引列表2
if username == 'Gaoli' and password == '123': # 如果名字是Gaoli,密码是123
print('Gaoli您好 文件正常执行')
else: # 否则
print('您不是Gaoli 无权执行该文件')
json模块
json模块也称为序列化模块 序列化可以打破语言限制实现不同编程语言之间数据交互
json格式数据的作用
json格式数据的形式
字符串类型并且引号都是双引号
json相关操作
针对数据
json.dumps()
json.loads()
针对文件
json.dump()
json.load()
json模块实战
# 用户登录注册功能
import os
import json
# 注册功能
# 1.获取执行文件所在的目录路径
base_dir = os.path.dirname(__file__)
# print(base_dir) # D:/pythonProject2/10-20
# 2.拼接出db目录的路径
db_dir = os.path.join(base_dir, 'db')
# print(db_dir) # D:/pythonProject2/10-20\db
# 3.创建db目录
if not os.path.isdir(db_dir):
os.mkdir(db_dir)
# # 4.获取用户数据
# username = input('username>>>:').strip()
# password = input('password>>>:').strip()
# # 4.1判断用户是否已存在(两种方式)
# # 方式1:
# print(os.listdir()) # ['jason.json', 'kevin.json', 'tony.json']
# # 方式2:
# user__file__path = os.path.join(db_dir, f'{username}.json')
# # 5.构造用户字典
# user_dict = {'username': username,
# 'password': password,
# 'account': 15000, # 账户余额
# 'shop_car': [] # 购物车
# }
# # 6.拼接存储用户数据的文件路径
# user__file__path = os.path.join(db_dir, f'{username}.json')
# # D:/pythonProject2/10-20/db/jason.json
# # 7.写入文件数据
# with open(user__file__path,'w',encoding='utf8') as f:
# json.dump(user_dict, f)
username = input('username>>>:').strip()
# 1.拼接上述用户组成的文件路径
target_user__file__path = os.path.join(db_dir, f'{username}.json')
if not os.path.isfile(target_user__file__path):
print('你走开-用户名都记不住')
else:
password = input('password>>>:').strip()
# 2.获取用户真实数据字典
with open(target_user__file__path, 'r', encoding='utf8') as f:
rea1_user_dict = json.load(f)
if password == rea1_user_dict.get('password'):
print('登录成功')
else:
print('密码错误')
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现