迭代器
![]()
常见内置函数(二)
# help() 查看注释信息
# help(len) 查看len函数的注释信息
# id() 返回相当于目标内存地址的一串数字
# print(id('name'))
# >>>18096640 相当于name字符串的内存地址
# int() 类型转换,进制转换,其他类型转成整形,其他进制转换成十进制
# res = '123'
# b = 0b101010
# print(int(res),type(res)) 字符串必须是纯数字,否则报错
# print(int(b))
# >>>123 <class 'str'>
# >>>42
# isinstance() 判断数据类型
# print(isinstance(12,str))
# print(isinstance(12,int))
# >>>False # 结果不是预期类型返回FALSE
# >>>True # 结果是预期类型返回True
# pow() 幂指数
# print(pow(2,3)) # 第一个参数为底数,第二个参数为指数
# >>>8
# round() 四舍五入
# print(round(11.6778,2)) # 第二个参数可以指定保留几位小数,不写默认一位小数
# print(round(11.5))
# >>>11.68
# >>>12
# sum() 求和
# print(sum([1,2,3,4,5,6,7,8,9]))
# >>>45
![]()
可迭代对象
# 1. 什么叫迭代?
迭代就是更新换代,每一次迭代的过程都要依赖于上一次的结果
'''
n = 1
while True:
print(n)
# 上述只是单纯的循环,没有结果的变化,不属于迭代
while True:
n += 1
print(n)
# 上述代码就属于迭代,因为结果每次都是根据上一次的在变化
l1 = [11, 22, 33, 44, 55]
# 迭代取值
i = 0
while i < len(l1):
print(l1[i])
i += 1
'''
# 2. 什么是可迭代对象?
可以点出__iter__方法的都可以称为可迭代对象
'''__iter__读作双下iter'''
# 3. 哪些数据类型是可迭代对象?
i = 11 # 整型不是
f = 11.11 # 浮点型不是
s = 'jason' # 字符是
l = [1,2,3,4] # 列表是
d = {'name':'jason','age':18} # 字典是
t = (1,2,3,4) # 元组是
se = {1,2,3,4,5} # 集合是
b = True # 布尔值不是
f = open() # 文件是
def index():pass # 普通函数不是
'''
属于可迭代对象的有
字符串、列表、字典、元组、集合、文件对象
可迭代对象其实就是为了后续迭代取值做准备
提供了不依赖于索引取值的方式
可迭代对象都可以进行for循环!
'''
迭代器对象
# 1. 什么是迭代器对象?
可迭代对象调用__iter__方法后生成的就是迭代器对象
# 2. 迭代器对象有什么特征?
可以点出__iter__和__next__方法
# 3. 如何理解迭代器对象
迭代器对象能够极大的节省存储空间,类似于工厂,只有你需要使用数据的时候他才给你数据,不需要使用他就是一个工厂壳子,只占工厂面积的空间
# 4. 迭代器对象如何取值?
调用__next__方法即可,调用一次给你一个值,取完了再取会直接报错!!!
ps:开辟了一种不需要索引取值的方式(for循环底层依据的就是迭代器对象)
'''有了迭代器对象才出现了针对字典和集合的迭代取值操作'''
# 5. 迭代器对象补充说明
# 1. 双下方法简写(不是所有双下方法都可以)
'''
__方法名__ 等价于 方法名()
__iter__ iter()
__next__ next()
'''
eg:
print(len([1,2,3,4,5,6]))
print([1,2,3,4,5,6].__len__())
运行结果:
6
6
# 2. 有些可迭代对象本身也是迭代器对象>>>:文件对象
# 3. 可迭代对象调用一次__iter__方法变成迭代器对象,继续调用结果还是迭代器对象,所以,文件本身既是可迭代对象又是迭代器对象,因为无论执行多少次__iter__,文件对象都还是迭代器对象
eg:
res = 'petter'
res1 = 'oscar'
print(res.__iter__())
print(res1.__iter__().__iter__().__iter__())
运行结果:
<str_iterator object at 0x020D8B30>
<str_iterator object at 0x020D8BF0>
# 无论执行多少次__iter__,结果都是iterator对象
# 4. 迭代取值的要求
'''迭代器对象每执行一次__next__,去除一个值'''
eg:
res = 'petter'
print(res.__iter__().__next__())
print(res.__iter__().__next__())
print(res.__iter__().__next__())
s = res.__iter__()
print(s.__iter__().__next__())
print(s.__iter__().__next__())
print(s.__iter__().__next__())
运行结果:
p
p
p
p
e
t
# 为什么前三次取值结果都是p,而后面三次是p e t?
'''
前三次取值,每次取值之前都把res执行了一遍__iter__,相当于每次取值前都把res初始化成一个新的迭代器对象,所以只能取出p,而后面s是res转换成的迭代器对象,迭代器对象再调用__iter__,结果还是他本身,哪怕你已经取过值了,结果还是本身,再取值也是接着后面取
'''
![]()
for循环的内部原理
# for循环内部就是一个迭代器
# 用迭代器输出列表
eg:
l1 = [1,2,3,4,5,6,7,8,9]
res = l1.__iter__()
i = 0
while i < len(l1):
print(res.__next__())
i += 1
运行结果:
1
2
3
4
5
6
7
8
9
# 通过结果可以看到,这段代码实现的功能和for循环数组l1的结果一毛一样,所以可以看出,for循环的本质就是通过迭代器挨个取值。这也是为什么可迭代对象都可以进行for循环
"""
for循环底层原理
for 变量名 in 可迭代对象:
循环体代码
1.会将in后面的数据调用__iter__()变成迭代器对象
为什么文件对象也可以for循环 因为本身就是迭代器对象 再次调用不变
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错误的类型
代码的报错也可以分为很多类型,错误类型会以Error结尾
3.name 'name' is not defined
具体的报错原因(就是解决报错的答案),可以把这一行放到百度搜,有奇效,具体报错内容跟在错误类型后面,还是找Error就可以了
# 3. 异常的分类
1. 语法异常
不被允许的,如果出错了必须立刻改正,代码运行不起来,必须改正后才可以跑起来
2. 逻辑异常
可以允许,如果出错了尽快修改,代码可以运行,但是得不到想要的结果
# 4. 异常的类型
# 异常的类型有很多,可以根据名字判断异常种类,如
NameError 名称错误
IndexError 索引错误
KeyError 键错误
# 异常类型都是由种类+Error组成,找到这个单词,照着名字翻译就可以
异常处理实操
'''有时候针对可能会出错的代码 也可以自己提前写好处理措施'''
正常情况下代码出错 肯定是直接导致程序停止
但是也可以自己通过代码来处理 从而避免程序的停止
# 基本语法结构
try:
可能出错的代码
except 错误类型1 as e: # e指代错误信息,此处语法类似于open
处理措施
except 错误类型2 as e:
处理措施
...
# 万能异常处理
try:
可能出错的代码
except Exception as e: # 当我们不知道会出什么类型的错时,就用这个也可以
处理措施
##############################################
异常处理使用准则
1.被检测的代码越少越好
2.能尽量少用就尽量少用
##############################################
![]()
异常处理了解
# 1. 和else连用
作用:当try监测的代码没有发生异常,正常运行过后执行else子代码
语法:
try:
可能出错的代码
except Exception as e:
处理措施
else:
没有出错执行的代码
# 2. 和finally连用
作用:无论try监测的代码有没有发生异常,执行完代码后都会执行finally子代码
语法:
try:
可能出错的代码
except Exception as e:
处理措施
finally:
异常处理后执行的代码
# 3. 全部整合到一起使用
try:
name
except Exception as e:
print(e)
else:
print('没报错 好极了')
finally:
print('管你错不错 都执行')
# 4.断言(了解中的了解)
作用:针对一个可能成立的结论进行预测,成功则没啥事,失败报错!!!
语法: assert 被断言内容
num = 1
assert isinstance(num,int) # num是int类型,程序正常运行
assert 1 > 2 # 1 < 2,程序报错
# 5.主动报错(需要掌握)
raise NameError('不爽 就要作!!!')
'''由于是主动报错 所以可以非常明确的知道错误的类型'''
![]()
用异常处理和迭代器实现自定义for循环
# 上面我们写了自定义for循环,当时我们自己定义了while循环结束条件,其实还可以用异常处理结束循环
eg:
l1 = [1,2,3,4,5,6,7,8,9]
# 迭代取值
res = l1.__iter__()
try:
while True:
print(res.__next__())
except Exception as e:
print(e)
运行结果:
1
2
3
4
5
6
7
8
9
# 这样写省去了计数的部分,更节省空间
# for循环本质:
进行了异常处理的迭代器
迭代取值与索引取值的对比
1. 索引取值
优势:可以重复取值,取值没有固定方向
劣势:只能支持有序的容器类型,无序的无法取值兼容新没有迭代取值高,且需要一个储存索引的内存空间,需要的空间资源更大
2. 迭代取值
优势:兼容所有的容器类型,不需要额外空间存储索引
劣势:只能从左往右取值,并且无法重复取值
# 真正底层的迭代取值后续可能很少用 一般都是for循环代替
"""
迭代器里面的东西是固定的 没取一个就会少一个 取完就空了
"""
![]()