Loading

可迭代对象,迭代器对象,异常操作

今日内容概要

  • 常见内置函数02
  • 可迭代对象
  • 迭代器对象
  • for循环的内部原理
  • 异常处理
  • for循环的本质(自己写代码模拟)

内容详细

常见的内置函数

  • help()查看注释信息
用法:
    1.help(len)
    2.def index():
    '''1231231231231'''
    pass
help(index)
  • id() 返回一串相对于内存地址的数字
print(id('123'))
括号内可以是函数名、变量名、字符串
  • int() 类型转换、进制转换
# 类型转换:
s = '123123'
s = int(s)
print(s,type(s))
# 进制转换
s = 123
print(bin(s))  # 0b1111011
print(int(0b1111011))  # 123
  • isinstance() 判断数据类型
s = '123123'
print(type(s) is str)  # True
'''上面这种方式在学了这个函数之后就不推荐使用了,别扭'''
print(isinstance(s,str))  # True
  • pow() 幂指数
print(pow(10,2))  # 前面那个是自然数,后面的是幂,这句话就是求出10的二次方等于多少
  • round() 四舍五入
print(round(111,1))  # 111
print(round(13.14,1))  # 13.1
print(round(13.36,1))  # 13.4
"""
如果第一个数是整数,不管要保留多少位,结果还是整数,不会给添加上小数点
"""

可迭代对象

# 什么是迭代:
	迭代其实就是更新换代,每一次迭代的过程都需要依赖于上一次的结果,目的通常是为了接近并到达所需的目标或结果。
    eg:游戏的更新就是版本的迭代

img

# 单纯的循环不是迭代
import time
while True:
    print(111)
    time.sleep(0.2)
并没有根据上一次的结果而产生新的结果
# 迭代的样子
n = 1
while n < 10:
    print(n)
    n += 1
# 迭代取值
l1 = [1,2,3,4,5,6]
n = 0
while True:
    print(l1[n])
    n += 1
# 可以取值,但是会报错
# IndexError: list index out of range

# 3.哪些数据是可迭代对象?
	依次列举并尝试调用__iter__方法即可
# 列表所学数据类型
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循环的
"""
属于可迭代对象的有
    字符串、列表、字典、元组、集合、文件对象
可迭代对象其实就是为了后续迭代取值做准备
    提供了不依赖于索引取值的方式
"""

迭代器对象

"""
什么是可迭代对象?
	内置有__next__方法的都可以称之为是可迭代对象
"""
# 迭代器对象的特征
含有__iter__方法和__next__方法
# 如何理解迭代器对象
迭代器对象能够极大的节省存储空间
eg:类似于哆啦A梦的口袋,不用的时候就是一个口袋面积,用的时候可以从中取出很多数据
	类似于一个工厂,有需要时才给生产东西
	类似于一个老母猪,想要猪仔就给你下一个
# 迭代器对象如何取值
	调用__next__方法即可  如果取完了则会直接报错
    而且__next__只能从左到右依次取值,不能循环取值
'''这是一种不需要索引取值的方式(for循环底层依据的就是迭代器对象)
有了迭代器对象才出现了针对字典和集合的迭代取值操作'''
# 定义可迭代对象,必须实现__iter__方法;定义迭代器,必须实现__iter__和next方法。

image-20220323180102999

迭代取值与索引取值的对比

1.索引取值
	优势:可以反复获取相同的元素,并且没有固定的方向
    劣势:只能支持有序的容器类型,无序的无法取值兼容性没有迭代取值高
2.迭代取值
	优势:兼容所有的容器类型
    劣势:取值的顺序永远都是从左往右,并且无法重复获取,取完了就没了
'''这种方法用的不多,一般都用for循环'''
'''迭代器里面的东西是固定的,每取一个就会少一个,取完就空了'''
迭代器很多对象补充说明
1.有很多上下方法都有简便写法 但不是全部
"""
__方法名__等价  方面名()
最常见的两个是
			__iter__    inter()
			__next__	next()
"""
print(l1.__iter__())  # <list_iterator object at 0x0000026D2D429470>
print(iter(l1))  # <list_iterator object at 0x0000026D2D429470>
print(l1.__next__())  # 1
print(next(l1))  # 2

2.有一些可迭代对象本身也是迭代器对象>>>:文件对象
3.可迭代对象调用一次__iter__方法编程迭代器对象  如果继续调用  结果还是迭代器对象本身
res = l1.__iter__()
res1 = l1.__iter__().__iter__().__iter__()
print(res,res1)
# <list_iterator object at 0x0000019BE5623748> <list_iterator object at 0x0000019BE5617278>
4.迭代取值的要求
l1 = [1, 2, 3, 4, 5, 6]
print(l1.__iter__().__next__())  # 1,每次都先产生一个新的迭代器对象然后取值
print(l1.__iter__().__next__())  # 1,每次都先产生一个新的迭代器对象然后取值
print(l1.__iter__().__next__())  # 1,每次都先产生一个新的迭代器对象然后取值
print(l1.__iter__().__next__())  # 1,每次都先产生一个新的迭代器对象然后取值
res = l1.__iter__()  # 已经变成迭代器对象了
print(res.__iter__().__next__())  # 1,之后再调用还是自身
print(res.__iter__().__next__())  # 2
print(res.__iter__().__next__())  # 3
print(res.__iter__().__next__())  # 4

总结

"""
1.可迭代对象实现了 __ iter __ 方法。
2.使用iter()函数判断可迭代对象更准确
3.任何序列都是可迭代对象
4.迭代器对象实现了 __ iter __ 和 __ next __方法。
5.迭代器是一个可以记住数据集里元素位置的对象,其内部有一个状态用于记录迭代所在的位置,以便下次迭代时候能取出正确的元素
"""

img

for循环内部原理

l1 = [1, 2, 3, 4, 5, 6]
'''需求,不依靠for循环完成对列表元素的取值'''
res = l1.__iter__()
n = 0
while n <len(l1):
    print(res.__next__())
    n += 1
  
"""
for循环底层原理
for 变量名 in 可迭代对象
	循环体代码
1. 会将in后面的数据调用__iter__()变成迭代器对象
为什么文件对象也可以for循环	因为本身就是迭代器对象,再次调用不变
2.针对产生的迭代器对象一次调用__next__()方法迭代取值
3.当值取完之后  会自动处理报错并退出循环
"""
# for 循环相当于:
res = l1.__iter__()
while True:
    print(res.__next__())

异常处理

什么是异常?
	代码运行出错之后就是异常,一场会导致程序立刻停止
'''
    异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行。
一般情况下,在Python无法正常处理程序时就会发生一个异常。
异常是Python对象,表示一个错误。
当Python脚本发生异常时我们需要捕获处理它,否则程序会终止执行。
'''
异常信息的组成部分
	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
    具体的报错原因,能够解决报错的答案,通常显示在最后一行
异常的分类
1.语法异常
	通常是语法上的错误,一般指代码语法结构不完善,写了一半的语法(不被允许的低级错误)
2.逻辑异常
	代码的逻辑出现了问题,出现了应该想办法解决(又叫BUG)
异常的类型(部分)
BaseException 所有异常的基类
SystemExit 解释器请求退出
KeyboardInterrupt 用户中断执行(通常是输入^C)
Exception 常规错误的基类
StopIteration 迭代器没有更多的值
GeneratorExit 生成器(generator)发生异常来通知退出
StandardError 所有的内建标准异常的基类
ArithmeticError 所有数值计算错误的基类
FloatingPointError 浮点计算错误
OverflowError 数值运算超出最大限制

异常处理操作

'''有时候针对可能出错的代码,也可以自己提前写好处理措施'''
正常情况下代码出错,肯定是直接导致程序停止
但是也可以自己通过代码来处理,从而避免程序的停止
基本语法结构
try:
    可能会出错的代码
except 错误的类型1 as e: # e指代的就是错误的提示信息
    针对性的处理措施
except 错误的类型2 as e:  # e指代的就是错误的提示信息
    针对性的处理措施
except 错误的类型3 as e:  # e指代的就是错误的提示信息
    针对性的处理措施
...
错误类型
很多时候可能自己都不知道会报什么类型的错误
  '''万能异常:常见的报错都可以照单全收'''
  try:
    可能会出错的代码
  except Exception as e:  
    统一的处理措施
异常处理使用准则
异常处理使用尊则
	1.被检测的代码越少越好
    2.能尽量少用就尽量少用

异常处理了解

结合else使用
当try检测的代码没有发生异常 正常运行完毕之后执行else的子代码
try:
    可能会出错的代码
except Exception as e:
    统一的处理措施
else:
    可能会出错的代码没有出错,最后走else子代码
结合finally使用
无论try检测的代码是否有异常,最后都被执行finally子代码
try:
    name
except Excepticon as e:
    print(e)
finally:
    print('无论try检测的代码是否有异常,最后都被执行finally子代码')
全部一起使用(报错,else,finally)
try:
	可能会出错的代码
except Exception as e:
    统一处理的措施
else:
    print('没报错~~~')
finally:
    print('错不错都执行')
断言
用于判断一个表达式,在表达式条件为 false 的时候触发异常。
断言可以在条件不满足程序运行的情况下直接返回错误,而不必等待程序运行后出现崩溃的情况
	name = 'tuzi'
	assert isinstance(name,str)
主动报错
raise NameError('我就想出错')
"""
由于是主动报错,所以非常明确的知道错误的类型
"""

for循环的本质

# 利用while与异常捕获,实现for循环的功能
l1 = [1,2,3,4,5]
res = l1.__iter__()  # 转为可迭代对象
while True:
    try:
        print(res.__next__())
    except StopIteration:  # 报错类型
        break  # 结束循环

preview

posted @ 2022-03-23 19:24  香菜根  阅读(33)  评论(0编辑  收藏  举报