本周总结4
异常处理
异常
异常就是代码运行报错,行业俗称叫bug
代码运行中一旦遇到异常会直接结束整个程序的运行,我们在编写代码的过程中要尽可能的避免
异常分类
语法错误
不允许出现,一旦出现立刻改正
逻辑错误
允许出现的,因为它一眼发现不了,代码运行之后才可能会出现
常见异常错误
常见的错误:
SyntaxError: 语法错误
NameError: 名字错误
IndexError: 索引错误
KeyError : 键错误
IndentationError :缩进错误
异常处理语法结构
try:
待检测的代码(可能会出错的代码)
except Exception as e: # e就是系统会提示的错误类型
针对错误类型要解决统一处理
else:
try子代码正常运行结束没有任何报错后,在执行else子代码
finally:
无论try的子代码是否报错,最后哦都要执行finally子代码
异常处理补充
1.断言assert
name = 'kiki'
# assert isinstance(name,int)
# print('肯定是字符串') # AssertionError
assert isinstance(name,str)
print('肯定是字符串') # 肯定是字符串
2.报错raise
name = 'kimi'
if name == 'kimi':
raise Exception('找到这里,说明我该走了')
else:
print('正常走')
生成器
生成器对象
1.生成器内置有__iter__和__next__方法,所以生成器本身就是一个迭代器
2.函数体代码中由yield关键字,那么函数名加括号并不会函数体代码,会生成一个生成器对象
生成器与迭代器的区别
迭代器对象是解释器自动提供的
数据类型/文件对象>>>:迭代器对象
生成器对象是程序员编写出来的
代码、关键字>>>:迭代器对象(生成器)
生成器的两种方法
yield关键字,我们就有了自定义迭代器的实现方向,yield可以用于返回值,但不同于return,函数一旦遇到return就结束了,而yield可以保存函数的运行状态挂起函数,用来返回多次值。
函数体代码中填写yield关键字
""" 1.函数体代码中如果由yield关键字,那么函数名加括号并不会执行函数体代码,会生成一个生成器对象(迭代器对象)"""
eg: def my_iter(): # 定义函数,先不执行
print('奶茶真好喝')
yield
res = my_iter() # 拿到生成器
""" 2.使用加括号之后的结果调用__next__才会执行函数体代码"""
eg1:
def my_iter():
print('奶茶真好喝')
yield
res.__next__() # 执行函数体,在yield后面停
""" 3.每次执行完__next__代码都会停在yield位置,下次基于这个位置继续往下找第二个yield """
""" 4.yield还有点类似于return 可以返回返回值"""
eg2:
def my_iter():
print('奶茶真好喝')
yield 110
print('果汁真好喝')
yield 120
print('火锅是真香')
yield 119
print('烧烤也不错')
yield 114
res = my_iter() # 生成生成器
r1 = res.__next__() # 执行到第一个yield停
print(r1)
r2 = res.__next__() # 执行到第二个yield停
print(r2)
r3 = res.__next__() # 执行到第三个yield停
print(r3)
r4 = res.__next__() # 执行到第四个yield停
print(r4)
代码结果展示 :
""" 奶茶真好喝
110
果汁真好喝
120
火锅是真香
119
烧烤也不错
114
"""
生成器对象实行range方法
# 1.两个参数
def my_range(start_num,end_num):
while start_num<end_num:
yield start_num
start_num+=1
for i in my_range(1,10):
print(i)
# 2.一个参数
def my_range(start_num, end_num=None):
if not end_num:
end_num = start_num
start_num = 0
while start_num < end_num:
yield start_num
start_num += 1
for i in my_range(10):
print(i)
# 3.三个参数
def my_range(start_num,end_num,step):
while start_num<end_num:
yield start_num
start_num +=step
for i in my_range(1,10,2):
print(i)
# 通用的方法
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(10):
print(i)
生成器冷门用法
def func(name,python=None):
print(f'{name}上课')
while True:
python = yield
print(f'{name}正在上课{python}')
res = func('kiki')
res.__next__()
res.send('化学课')
生成器表达式
# 列表生成式
l1 = [i**2 for i in range(10)]
print(l1)
# 生成器表达式
l2 = (i*2 for i in range(10))
print(l2)
for i in l2:
print(i)
模块
索引取值和迭代取值的差异
l1 = [11,22,33,44,55,66,77,88,99]
1.索引取值
可以任意位置 任意次数取值
eg:l1[2] = 33 l1[1] =22 l1[2] = 33
不支持无序类型(如字典)的数据取值
2.迭代取值
只能从前往后依次取值无法后退
eg: 11,22,33....99
支持所有类型的数据取值(有序无序类型都可)
模块简介
在python中,一个py文件就是一个模块,文件名为xxx.py模块名则是xxx,导入模块就可以使用已经写好的功能。程序中的模块可以被重复使用,既保证了代码的重用性,又增强了程序的结构和可维护性
1.模块的本质
内部具有一定功能的py文件
2.python模块的历史
初期被其他编程语言的程序员称为‘调包侠’,后期不得不使用python>>>:真相定律
3.python模块的表现形式
3.1 Py文件(py文件也可以称为是模块文件)
3.2 含有多个py文件的文件夹(按照模块功能的不同划分不同的文件夹存储)
3.3 已被编译为共享库或DLL的C或C++扩展(了解)
3.4 使用c编写并链接到python解释器的内置模块(了解)
模块分类
1.自定义模块
我们自己写的模块文件
2.内置模块
python解释器提供的模块 time
3.第三方模块
别人写的模块文件(python背后真正的大佬)
导入模块的两种句式
1.import句式
以import aa 为例研究底层原理
"""
1.先产生执行文件的名称空间
2.执行被导入文件的代码将产生的名字放入被导入文件的名称空间中
3.在执行文件的名称空间中产生一个模块的名字
4.在执行文件中使用该模块名点的方式使用模块名称空间中所有的名字
import aa # 导入模块aa
name = 'kiki'
print(aa.name) # 打印引用模块aa中全局变量name的值
aa.func1() # 调用模块aa中func1函数
aa.func2() # 调用模块aa中func2的函数,等于再次调用模块aa中的func1函数
aa.change() # 调用模块aa中change的函数,模块aa的全局变量name='kimi'修改为name='rose'
print(aa.name)
print(name)>>>>:执行文件中的全局变量name
"注意:若想要执行当前文件中的名称空间中存在的name,执行aa.get()操作的都是源文件中的全局变量name"
2.from…import…
以from...import...name,func1为例研究底层原理
"""
1.先产生执行文件的名称空间
2.执行被导入文件的代码将产生对应的名字放入被导入文件的名称空间中
3.在执行文件的名称空间中产生对应的名字绑定模块名称空间中对应的名字
4.在执行文件中直接使用名字就可以访问名称空间中对应的名字
from aa import name,func1,func2,change # 导入模块aa中的全局变量name,函数func1,func2,change
print(name) # 打印模块aa中的全局变量name的值
func1() # 调用模块aa中func1函数
func2() # 调用模块aa中func2函数
change() # 调用模块aa中change函数
print(name) # kimi
'''
change是aa中的change,
change代码中的global name是aa全局的name,
所以不会影响执行文件的name
'''
导入模块的句式补充
1.import与from...import....两者优缺点
由于使用模块名称空间的名字都需要模块点的方式才可以用
所以不会轻易的被执行文件中的名字换掉
但是每次使用模块名称空间中的名字都必须使用模块点才可以
from...import...句式
指名道姓的导入模块名称空间中需要使用的名字,不需要模块点
但是容易跟执行文件的名字冲突(执行文件有name,导入模块也有name)
2.重复导入模块
解释器只会导入一次,后续重复的导入语句并不会执行
eg: import aa # 导入模块aa
import aa
import aa
'只执行导入一次'
3.起别名
import zhongguorenming as zg
from zhongguorenming import zhosngdeineidiedideh as f1
from zhongguorenming import name as n,func1 as f
4.涉及到多个模块导入
如果模块相似度不高,推荐使用
import aa
import zhongguorenming
如果模块相似度高,推荐使用
import aa, zhongguorenming
循环导入问题及解决策略
1.循环导入
两个文件之间彼此导入彼此并且相互使用各自名称空间中的名字 极容易报错
2.如何解决循环导入问题
1.确保名字在使用之前就已经准备完毕
name = 'from my2' # 把name的值放在是使用之前的位置
import my1
print(my1.name)
2.我们以后在编写代码的过程中尽可能避免出现循环导入
判断文件类型
所有的py文件都可以直接打印__name__对应的值
当py文件是执行文件的时候__name__对应的值是__main__
eg: print(__name__) # __main__
当py文件是被导入文件的时候__name__对应的值是模块名
eg:import my2 # 执行文件my1 结果是my2
if __name__=='__main__': # 快捷键(敲main回车就会出来)
print('哈哈哈,我是执行文件 我可以运行这里的子代码')
上述脚本可以用来区分所在py文件内python代码的执行
使用场景
1.模块开发阶段
2.项目启动文件
"""
执行文件里面:
from a import * # *默认是将模块名称空间中所有的名字导入
被导入文件里面:
__all__ = ['名字1','名字2'] 针对*可以限制拿到的名字
不能拿模块中没有的名字
"""
模块的查找顺序
1.内存
import aaa
import time
time.sleep(5)
print(aaa.name)
aaa.func()
'先从内存中中,即使加载后再删除了aaa文件,本次加载还能加载出来name,但是第二次运行之后就会报错,因为此时的aaa文件已经被删除了'
2.内置
import time
print(time) # <module 'time' (built-in)>
print(time.name) # module 'time' has no attribute 'name' 内置time没有name的
'以后在自定义模块的时候尽量不要与内置模块名冲突'
3.执行文件所在的sys.path(系统环境)
一定要以执行文件为准!!!
我们可以将模块所在的路径也添加到执行文件的sys.path中即可
# import ddd
# print(ddd.name) # 报错 当ddd不属于当前执行文件的同级文件时需要添加绝对路径进去
import sys
print(sys.path) # 列表 一般只看第一个路径
sys.path.append(r'D:\PycharmProjects\test17\myname')
import ddd
print(ddd.name) # kiki
绝对导入和相对导入
绝对导入
from myname import ddd
print(ddd.name) # kiki
from aaaa.bbbb.cccc.dddd import name # 可以精确到变量名
print(name) # 我是dddd文件
from aaaa.bbbb.cccc import dddd # 也可以精确到其模块名
print(dddd.name) # 我是dddd文件
ps:套路就是按照项目根目录一层层往下查找
相对导入
. 在路径中表示当前目录
.. 在路径中表示上一层目录
..\.. 在路径中表示上上一层目录
不再依据执行文件所在的sys.path而是以模块自身路径为准
from.import b
相对导入只能基于模块文件中,不能在执行文件中使用
""" 相对导入使用频率较低,一般用绝对导入即可,结构更加清晰 """
包
包的概念
大白话:多个py文件的集合>>>:文件夹
专业:内部含有__init__.py文件的文件夹(python2必须要求,python3无所谓)
包的具体使用
虽然python3对包的要求降低了,不需要__init__.py也可以识别,但是为了兼容性考虑,最好还是加上__init__.py
1.如果只想用包中某几个模块,那么还是按照之前的导入方式即可
from aaa import my1 my2
2.直接导包名
import aaa
导入包名其实就是导包下面的__init__.py文件,该文件内有什么名字就可以通过包点什么名字
""" 如果单独import aaa(包名),只能导入aaa包的__init__.py文件,要是想一次性导入aaa包名下的a.py文件,提前在__init__.py中导入a.py文件"""
编程思想的转变
1.面条版阶段
所有的代码全部堆叠在一起(if elif elif elif else)
2.函数版阶段
根据功能的不同封装不同的函数(func_dict)
3.模块版阶段
根据功能的不同拆分成不同的Py文件
4.面对对象
"""
第一个阶段可以看成是直接将所有的数据放在c盘
视频 音频 文本 图片
第二个阶段可以看成是将c盘下的数据分类管理
视频文件夹 音频文件夹 文本文件夹 图片文件夹
第三个阶段可以看成事将C盘下的数据根据功能的不同划分到更合适的位置
系统文件夹 C盘
视频文件夹 D盘
图片文佳夹 E盘
>>>>>:目的为了资源的高效管理
软件开发目录规范
软件开发目录规范
project
bin 存放项目启动文件
start.py 项目启动文件
conf 项目配置文件
settings.py 存放项目默认配置 一般全大写
core 项目核心文件(业务逻辑相关代码)
src.py 核心功能
interface 项目接口文件
user.py 根据具体业务逻辑划分对应的文件
account.py
db 存放相关项目数据(与数据库交互)
userinfo.txt
db_handler.py
lib 存放项目公共文件
common.py 自定义文件
log 存放项目日志文件
log.log
README 项目说明书
requirements.txt 主要存放项目所需的模块和版本
python常用内置模块
常见的内置数据:
常见的内置数据类型:
dict、list、set、tuple
collections模块还提供了几个数据类型:
1.Counter 计时器,主要用来计数
2.deque 双端队列,可以快速的从另外一侧追加和推出对象
3.defaultdict 带有默认值的字典
4.namedtuple 生成可以使用名字访问元素内容的tuple
5.OrderDict 有序字典
collection模块
1.具名元组:namedtuple
eg1:表示二维坐标系
from collections import namedtuple
point = namedtuple('点',['x','y'])
# 生成点的信息
p1 = point(120,110)
print(p1) # 点(x=120, y=110)
print(p1.x) # 120
print(p1.y) # 110
2.deque 双端队列
队列和堆栈
队列:先进先出
堆栈:先进后出
队列和堆栈都是一边只能进一边只能出
队列通常是在入队时在队尾添加元素,在出队时,队头弹出元素,而双端队列没有这样的输入输出的限制.这里collections模块中的deque就是双端队列。
代码实现:
使用list 存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,这个时候引入了deque,可以高效的帮助我们插入和删除列表,适合用于队列和栈
from collections import deque
q1 = deque(['a','b'])
q1.append('B')
print(q1)
q1.pop()
print(q1)
q1.appendleft('A')
print(q1)
q1.pop()
print(q1)
3.OrderedDict 有序字典
使用dict,key是无序的,在对dict做迭代时,我们无法确定key的顺序,此时我们使用collection的OrderedDict,可以保持字典的键是有序的
from collections import OrderedDict
d = dict([('a',1),('b',2),('c',3)])
print(d) # {'a': 1, 'b': 2, 'c': 3} 字典的key是无序的
d1 = OrderedDict([('a',1),('b',2),('c',3)])
print(d1) # OrderedDict([('a', 1), ('b', 2), ('c', 3)]) OrderedDict的key是有序的
注意:OrderedDict 的key会按照插入的顺序排列,不是key本身排列
4.defaultdict 默认字典
使用dict
时,如果引用的Key不存在,就会抛出KeyError
。
如果希望key不存在时,返回一个默认值,就可以用`defaultdict
from collections import defaultdict
dd = defaultdict(lambda: 'N/A')
dd['key1'] = 'abc'
dd['key1'] # key1存在
# 'abc'
dd['key2'] # key2不存在,返回默认值
# 'N/A'
时间模块
三种时间表现形式
1.时间戳 time.time()
秒数
2.结构化时间
主要是给计算机看的,人看不适应
3.格式化时间
主要是给人看的
Y m d H M S X
年 月 日 时 分 秒 时:分:秒
time模块
# 导入时间模块
import time
# 时间戳
time.time()
print(time.time()) # 1666165810.4114015
# 时间字符串
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 15:56:52
print(time.strftime('%Y/%m/%d %X')) # 2022/10/19 15:56:52
datetime模块
import datetime
b = datetime.datetime.now()
print('当前日期:',b) # 当前日期: 2022-10-19 16:16:16.266254
print(datetime.datetime.today()) # 2022-10-19 16:17:29.847966
print(datetime.date.today()) # 2022-10-19
随机数模块
1.导入模块
# 导入随机数
import random
2.随机小数random() uniform()
print(random.random()) #大于0小于1之间的小数 0.8705054721763096
print(random.uniform(1,5)) # 大于1小于5的小数 1.250392711400564
3.随机整数 randint() randrange()
print(random.randint(1,6)) # 随机产生1-6之间的整数
print(random.randrange(1,100,2)) # 随机产生指定的整数1-100之间的奇数
4.随机选择一个或多个样本 choice choices sample
print(random.choice(['一等奖','二等奖','三等奖','欢迎再来'])) # 随机抽取一个样本 三等奖
print(random.choices(['一等奖','二等奖','三等奖','欢迎再来'])) # 随机抽取一个样本 ['二等奖']
print(random.sample(['kiki','kimi','rose','kevin','jerry','lili'],2)) # 随机抽取样本数 ['kimi', 'jerry']
5.打乱列表顺序
l1 = [3,5,6,9,67,4,34,97,34,'A','G','J','K','B','L']
random.shuffle(l1)
print(l1) # 随机打乱数据集[34, 4, 'A', 67, 'L', 'G', 9, 97, 6, 5, 34, 3, 'J', 'K', 'B']
随机生成图片验证码
import random
def get_code(n):
code = ''
for i in range(n):
random_upper = chr(random.randint(65,90))
random_lower = chr(random.randint(97,122))
random_int = str(random.randint(1,9))
temp = random.choice([random_int,random_lower,random_upper])
code +=temp
return code
res = get_code(8)
print(res)
os与sys模块
os与sys模块的区别
os模块主要与操作系统打交道
sys模块主要与python解释器打交道
os模块
1.创建目录
os.mkdir 单级
os.makedirs 多级
2.删除目录
os.rmdir
os.removedirs
3.列举指定路径下内容
os.listdir
4.删除或重命名
os.remove
os.rename
5.获取/切换当前工作目录
os.getcwd()
os.chdir('..')
6.动态获取项目跟路径
os.path.abspath(__file__)
os.path.dirname(__file__)
7.判断路径是否存在
os.path.exists
os.path.isfile
os.path.isdir
8.路径接口
s1
s2
os.path.join(s1,s2)
9.获取文件大小
os.path.getsize
sys模块
import sys
print(sys.path) # 获取执行文件的sys.path
print(sys.getrecursionlimit()) # 获取python解释器默认最大递归深度
print(sys.setrecursionlimit(2000)) # 修改python解释器默认最大递归深度 None
print(sys.version) # 3.8.6 (tags/v3.8.6:db45529, Sep 23 2020, 15:52:53) [MSC v.1927 64 bit (AMD64)] 查看系统版本信息
print(sys.platform) # 平台信息 win32 (了解即可)
res = sys
if len(res) != 3:
print('执行命令缺少了用户名或密码')
else:
username = res[1]
password = res[2]
if username == 'kiki' and password == '123':
print('kiki,您的文件正在正常执行')
else:
print('你不是kiki,无权执行该文件')
json模块
引入:字典转为str(字典)很简单,但是str(字典)如何转为字典呢,下面就引入了json模块,可以帮我实现这个功能。
json模块也称为序列化模块,序列化就是将原本的字典、列表等内容转换成一个字符串的过程。序列化可以打破语言限制实现不同的编程语言之间数据交互。
序列化的目的:
1.以某种存储形式是自定义对象持久化
2.将对象从一个地方传递到另一个地方
3.使程序更具维护性
json相关操作
针对数据
json.dumps()
json.loads()
针对文件
json.dump()
json.load()
序列化
import json # 引入json
方式一:dumps
with open(r'aa.py','w',encoding='utf8') as f2:
json_str = json.dumps(d1) # '{}' 序列化:数据类型>>>json格式字符串
f2.write(json_str) # # 将序列化的文本写进文件,并以{"name": "rose", "pwd": 666}形式展示
方式二:dump
with open(r'aa.py','w',encoding='utf8') as f2:
json.dump(d1,f2) # 将数据序列化并写入文件 {"name": "rose", "pwd": 666}
反序列化
import json # 引入json
方式一:dumps
with open(r'aa.py','w',encoding='utf8') as f2:
json_str = json.dumps(d1) # '{}' 序列化:数据类型>>>json格式字符串
f2.write(json_str) # # 将序列化的文本写进文件,并以{"name": "rose", "pwd": 666}形式展示
方式二:dump
with open(r'aa.py','w',encoding='utf8') as f2:
json.dump(d1,f2) # 将数据序列化并写入文件 {"name": "rose", "pwd": 666}
原文地址:http://www.cnblogs.com/zhanglanhua/p/16819616.html