Day16课后有感
今日内容概要
- 常见内置函数02
- 可迭代对象
- 迭代器对象
- for循环的内部原理
- 异常处理
- for循环的本质(自己写代码模拟)
常见内置函数
1. help() # 查看注释信息 help(len) # 查看len如何使用 2. id() # 返回一串相当于内存地址的数字 print(id('anna')) # 返回一串数字(内存地址) 3. int() # 类型转换、进制转换 4. isinstance() # 判断数据类型 print(type('anna')is str) # 类型判断 很别扭 所以不推荐这种方式书写 print(isinstance('anna', str)) # True 代码中放一个数据类型str,进行判断 print(isinstance('anna', int)) # False # 一般一个变量名或者方法名前面用is开头一般得到的值或者返回值是布尔值 5. pow() # 幂指数 print(pow(10, 2)) # 求10的2次方 6. roud() # 四舍五入 print(round(11,1)) # 11 第二个参数控制需要保留几位小数部分 print(round(11.29, 1)) # 11.3 print(round(11.59)) # 12 7. sum() # 求和 print(sum[11,22,33,4,5]) # 里面放一个可以支持for循环的
可迭代对象
1. 什么叫迭代?
迭代其实就是更新换代,每一次迭代都需要依赖上一次的结果,比如说游戏的更新就是一种版本的的迭代
举个🌰
import time # 输入时间 while True: print(123) time.sleep(0.1) # 单纯的循环 不是迭代 n = 1 while True: print(n) n += 1 # 依赖于上次结果的n+1再加1,符合迭代要求 l1 = [11, 22, 44, 3, 5] n = 0 while n < len(l1): print(l1[n]) n += 1 # 迭代取值,也符合迭代要求
2. 什么是可迭代对象?
内置有__iter__方法的都可以称之为是可迭代对象
大白话就是数据可以通过点的方式点出来__iter__
__iter__该类代码的读法>>>:双下iter方法
3. 哪些数据是可迭代对象?
把所有数据依次列举用点的方式点出来__iter__的都是可迭代对象
尝试所学数据类型是否是可迭代对象:
i = 11 # 整型不是 f = 11.11 # 浮点型不是 s = 'anna' # 字符是 l = [1, 2, 3, 4] # 列表是 d = {'name': 'anna', 'age': 18} # 字典是 t = (1, 2, 3, 4) # 元祖是 se = {1, 2, 3, 4, 5} # 集合是 b = True # 布尔值不是 f = open() # 文件是 def index():pass # 普通函数不是 # 字符串、列表、字典、元祖、集合、文件对象都是属于可迭代对象,都是为了后续迭代取值做准备,提供了不依赖于索引取值的方式
迭代器对象(iterator object)
1. 什么是迭代器对象
res = s.__iter__()
print(res) # <str_iterator object at 0x117a62d68> 可迭代对象调用__iter__方法之后生成的结果就是迭代器对象
2. 迭代器对象的特征
含有__iter__ 和__next__方法
3. 如何理解迭代器对象
迭代器对象能够极大的节省存储空间
举个🌰
类似于哆啦A梦的口袋,不用的时候只是一个口袋的面积,但是能从口袋中取出很多数据,类似于文件中压缩包的概念
我们之前学过的range功能就是个迭代器对象
4. 迭代器对象如何取值
调用__next__方法即可
举个🌰
s = 'anna' res = s.__iter__() print(res.__next__()) # a 依次取值 print(res.__next__()) # n print(res.__next__()) # n print(res.__next__()) # a print(res.__next__()) # 取完后再取会直接报错
开辟了一种不需要索引取值的方式,现有迭代器才有了for循环,for循环底层依据的就是迭代器对象
有了迭代器对象才出现了针对字典和集合的迭代取值操作
5. 迭代器对象补充说明
1. 可以用简便的写法:
__方法名__ 等价 方法名()
__iter__ iter()
__next__ next()
__len__ len()
2. 文件对象>>>: 即是可迭代对象也是迭代器对象
f点即可以__iter__也可以__next__
为什么文件对象也可以for循环 因为本身就是迭代器对象 再次调用结果不变
3. 可迭代对象调用一次__iter__变成迭代器对象,如果继续调用,结果不变,还是迭代器对象本身
s = 'anna'
res = s.__iter__
res1 + s.__iter__().__iter__().__iter__() print(res, res1) # 两者结果是一样的
4. 迭代取值的要求
s = 'anna' print(s.__iter__().__next__()) # a 每次先产生一个新的迭代器对象然后取值 print(s.__iter__().__next__()) # a print(s.__iter__().__next__()) # a print(s.__iter__().__next__()) # a res = s.__iter__() # 已经变成迭代器对象了 print(res.__iter__().__next__()) # a 之后再调用结果还是自身 print(res.__iter__().__next__()) # n print(res.__iter__().__next__()) # n print(res.__iter__().__next__()) # a
for循环内部原理
举个🌰
需求:不依赖for循环 完成对列表元素的取值
l1 = [11, 22, 3, 44, 55] res = l1.__iter__() # 先变个形 n = 0 while n < len(l1): # 加个结束条件 print(res.__next__()) # 再取个值 n += 1
for循环底层原理
for 变量名 in 可迭代对象:
循环体代码
1. 会将in后面的数据调用__iter__()变成迭代器对象
2.针对产生的迭代器对象依次调用__next__()方法迭代取值
3.当值取完后,会自动处理报错并退出循环
异常处理
1.什么是异常?
代码运行出错了,程序异常了出错了,程序就会立刻停止,运行结果飘红,程序猿最怕的东西:bug
2.异常组成的部分
举个🌰
Traceback (most recent call last): # 异常来源
File "/Users/jiboyuan/PycharmProjects/day16/05 异常处理.py", line 3, in <module>
name
NameError: name 'name' is not defined
1.line关键字所在的一行
用于提示你代码哪一行出错了 点击前面的蓝色字体可以直接定位
'''如果报错的信息很长 一般最后一个才是'''
2.NameError错误的类型
代码的报错也可以分为很多类型
3.name 'name' is not defined
具体的报错原因(就是解决报错的答案)
3. 异常的分类
1.语法异常
不被允许的 如果出现了必须立刻改正
eg:if分支结构都不会写...
2.逻辑异常
可以允许的 如果出现了尽快修改即可
eg:代码动态获取到了一个字符串类型的数据但是调用了列表的内置方法
name = 'jason'
print(name.append())
# 改bug其实就是在重新梳理你的思路
3.异常的类型(有很多 不一一列举)
print(name) # NameError 名字错误
l1 = [11, 22, 33]
print(l1[100]) # IndexError 索引错误
d = {'name':'jason'}
print(d['age']) # KeyError 键错误
int('jason') # ValueError 值错误
异常处理实操
'''有时候针对可能会出错的代码 也可以自己提前写好处理措施'''
正常情况下代码出错 肯定是直接导致程序停止
但是也可以自己通过代码来处理 从而避免程序的停止
# 基本语法结构
try:
可能会出错的代码
except 错误的类型 as e: # e指代的就是错误的提示信息
# 针对性的处理措施
举个🌰
try: print(name) int('anna') except NameError as e: print('变量名没有定义就使用了 你是不是傻!!!') except KeyError as e: print('键出问题了') except ValueError as e: print('值出问题了') except IndexError as e: print('索引出问题了')
以上方法比较繁琐,还有一种万能异常
很多时候可能自己都不知道会报什么类型的错误
'''万能异常:常见的报错都可以照单全收'''
try:
可能会出错的代码
except Exception as e:
统一的处理措施
##############################################
异常处理使用准则
1.被检测的子代码越少越好
2.能尽量少用就尽量少用
##############################################
异常处理(了解)
1.结合else使用 当try检测的代码没有发生异常 正常运行完毕之后执行else的子代码 try: 可能会出错的代码 except Exception as e: 统一的处理措施 else: 可能会出错的代码没有出错 最后走else子代码 2.结合finally(最后)使用 无论try检测的代码是否有异常 最后都会执行finally子代码 try: name except Exception as e: print(e) finally: 无论try检测的代码是否有异常 最后都会执行finally子代码 3.全部整合到一起使用 try: name except Exception as e: print(e) else: print('没报错 好极了') finally: print('管你错不错 都执行') 4.断言(了解中的了解) # 提前预测 name = 'jason' assert isinstance(name,str) 5.主动报错(需要掌握) raise NameError('不爽 就要作!!!') '''由于是主动报错 所以可以非常明确的知道错误的类型'''
for循环的本质
利用while与异常捕获 实现for循环的功能
info = {'name': 'anna', 'age': 16, 'pwd': 188} # 1.先转换成迭代器对象 res = info.__iter__() # res = iter(info) # 也可以简写上行代码 # 2.迭代取值 while True: try: print(res.__next__()) # print(next(info)) # 也可简写上行代码 except StopIteration as e: # 结束while循环 break
迭代取值与索引取值的对比
1.索引取值
优势:可以反复获取相同的元素 并且没有固定的方向
劣势:只能支持有序的容器类型 无序的无法取值兼容性没有迭代取值高
2.迭代取值
优势:兼容所有的容器类型
劣势:取值的顺序永远都是从左往右 并且无法重复获取 去完就完了
# 真正底层的迭代取值后续可能很少用 一般都是for循环代替
"""
迭代器里面的东西是固定的 没取一个就会少一个 去完就空了
"""