本篇目录
一、异常
1.1 常见标准异常
- 异常名称
异常名称 注释 AssertionError 断言语句失败抛出 AttributeError 尝试访问未知的对象属性 IndexError 索引超出序列的范围 KeyError 字典中查找一个不存在的关键字 KeyboardInterrupt 用户输入中断键(Ctrl+c) MemoryError 内存溢出(可通过删除对象释放内存) NameError 尝试访问一个不存在的变量 OSError 操作系统产生的异常(例如打开一个不存在的文件) OverflowError 数值运算超出最大限制 SyntaxError Python的语法错误 ZeroDivisionError 除数为零
1.2 异常检测及处理
- 标准模板
# 监控语句块1,并捕获抛出的异常给except try: # 出错点以后的语句不会被执行 语句块1 # 若出现异常名称1,程序会执行语句块2 except 异常名称1: 语句块2 # 多异常捕获(未列出的异常则正常抛出,且程序中断) except 异常名称2,异常名称3 语句块3 # 处理完try语句和except语句之后一定会执行的语句(即使有未捕获的异常) finally: 语句块4
- 异常引出
# 主动引出异常:任何位置都可直接触发任何设定的异常 raise ZeroDivisionError # 断言语句:断定表达式是True,否则,抛出asserterror异常 num = 1 assert 1 == num
二、迭代器
2.1 概念
- 常规可迭代对象:列表、元组、字典、集合
- 迭代器:操作迭代器可以依次读取可迭代对象的每一个值
- 一次性:迭代到尾部,再操作迭代器会持续报错
- 单向性:只可向队尾,不可指定方向及位置
2.2 构建及使用
- 构建、判断迭代器
# 操作列表 In [1]: num = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # num_iter类型:返回迭代器, In [2]: num_iter = iter(num) # 判断是否为迭代器方法: In [3]: from collections.abc import Iterator In [4]: isinstance(num_iter, Iterator) Out[4]: True
- 使用迭代器
# 方法一:若越界,见下面的越界异常 In [5]: next(num_iter) Out[6]: 0 # 方法二:若越界,见下面的越界异常 In [7]: num_iter.__next__() Out[7]: 1 # 方法三:遇到越界自动退出,不抛异常 In [8]: for i in num_iter: ...: print(i, end=" ") # 注意体会迭代器的单向性、一次性 2 3 4 5 6 7 8 9 # 方法四:列表、元组化迭代获取 # 1.列表化获取:首先重置迭代器 In [9]: num_iter = iter(num) In [10]: list(num_iter) Out[10]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 2.元组化获取:首先重置迭代器 In [11]: num_iter = iter(num) In [12]: tuple(num_iter) Out[12]: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
- 越界异常
# 越界:抛出StopIteration异常 In [13]: next(num_iter) -------------------------------------- StopIteration
三、生成器
-
概述:其本质就是迭代器,对于庞大的可迭代对象,生成器只定义生成规则,不实际生成,每次调用生成器即只生成一个数据,节省内存,效率更高
-
生成器表达式
# 创建:涵盖0~10000000的数的平方生成规则 # 注意与列表生成式区别,其为[] g = (x * x for x in range(10000000)) type(g) >>> generator # 其也是迭代器 isinstance(g, Iterator) >>> True # 生成器调用:同迭代器
-
生成器函数
def c_gen(): num = 1 while True: # yield语句:含此语句则为生成器函数 yield num num += 1 f = c_gen() # f为生成器 type(f) >>> generator # 生成器调用:同迭代器
-
运行流程:
- 调用生成器函数,内存加载生成器函数,生成器运行到yield语句,暂停,
生成器函数若未越界则驻留内存 - 将值(num)弹给调用处,跳出生成器,并记录跳出点
- 下次生成器再次被调用,则从上次跳出的yield下一条语句继续执行
- 调用生成器函数,内存加载生成器函数,生成器运行到yield语句,暂停,
四、装饰器(函数式编程)
- 功能:在不改变原有函数的基础上增加新功能的机制,装饰器可以加在多个函数身上,来为函数增加装饰器所具有的功能,而调用的函数名还是原函数名
4.1 闭包(装饰器理解的基础)
4.1.1 定义
- 闭包函数:声明在一个函数中的函数,叫做闭包函数
- 闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。
- 特点:可以避免使用全局变量,防止全局变量污染;让外部访问函数内部变量成为可能;会造成内存泄漏(有一块内存空间被长期占用,而不被释放)
4.1.3 实例
- 代码示例
# outer是外部函数 a和b都是外函数的临时变量,功能实现结束后 # 会自动在内存中销毁outer所指向的内存,见下解释 def outer( a ): b = 10 # inner是内函数,闭包函数,因创建outer时才会创建inner # 所以每次创建都彼此独立,见下解释 def inner(): # 在内函数中,用到了外函数的临时变量 print(a+b) # 外函数的返回值是内函数的引用 return inner if __name__ == '__main__': # 返回了函数名inner,且a和b的值都已确定, # 只是做了个引用,不会有任何显示 demo1 = outer(5) # 相当于inner(),且其内的a,b值都已确定 demo1() # 此处即使改变outer()的函数体,demo()的值也不会改变, # 但会影响demo2 demo2 = outer(7) # 打印输出17 demo2()
- demo1定义:
demo1 = outer(5)
- 我们调用outer函数,outer函数创建了inner函数,然后把inner函数的引用返回并存给了demo
- 外部函数
outer()
结束任务,启动销毁 - 外函数销毁的时候发现内部函数将会用到自己的临时变量,这两个临时变量就不会释放,会绑定给这个内部函数,内部函数inner因为被外部的demo引用,也不能销毁,所以只有
def行
、return行
销毁,其他常驻内存
- demo1使用:
demo1()
- demo()的函数名demo此时包含了两个内在属性,def inner() 和变量b = 10, a
- 变量b只读:因为变量b是inner()函数的外部变量,又因为外部函数可以读取并修改内部函数的变量,内部函数只可向上逐层读取外部函数的变量,但不可修改外部函数的变量
- 不可变性:因为demo = outer(5)语句后,inner函数和外部变量b就常驻内存了,整个程序不结束,二者的函数体和变量值就不可变,即不可变性
- demo2定义:
demo2 = outer(7)
- 与
demo1 = outer(5)
同样绑定流程及销毁流程 - 常驻内存部分:其常驻内存部分与
demo1 = outer(5)
的常驻内存部分各自独立,完全不相关,无限制创建会导致内存泄露
- 与
4.2 装饰器构建
- 多个装饰器:其应用顺序是按照自底向上的
- 核心点:装饰器核心点是针对函数名的运算
- 无输入值的装饰器
# 装饰器定义:定义无输入值(除了函数名func)的闭包, # func为外部嵌套函数中的变量 def c_dec(func): # 闭包要素一:内部函数wrapper_in(*argv,**kw) def wrapper_in(*argv,**kw): # 顺序执行语句一: 此处为新增的功能,每次重写这里即可 # 其他位置都是不变的 print('这是内函数语句') # 顺序执行语句二:执行原函数 # 闭包要素二:调用了外部函数的变量 func(*argv,**kw) # 闭包要素三:返回内嵌函数名 return wrapper_in ######################################################### # 装饰器使用:功能相当于语句 now = c_dec(now) @c_dec def now(*argv,**kw): # 函数功能就是:传进来什么就打印什么 print(*argv,**kw) ######################################################### # 调用now函数:此时 now('good') # 等价于 c_dec(now)('good') # 等价于 wrapper_in('good') now('good') ######################################################### >>>这是内函数语句 >>>good
- 有输入值的装饰器
# 首层传装饰器的输入值:多层嵌套实现传参 def c_dec(text): def decorator(func): # --------跟无输入值装饰器一样:起始-------- def wrapper_in(*args, **kw): # 顺序执行语句一: 此处为新增的功能,每次重写这里即可 # 其他位置都是不变的 print("接收到的字符串是:" + text) # 这是执行被修饰的原函数 func(*args, **kw) return wrapper_in # --------跟无输入值装饰器一样:结束--------- return decorator ######################################################### # 传入参数的装饰器:字符串传给c_dec函数 @c_dec('execute') def now(*args,**kw): print(*args,**kw) ######################################################### # 调用now函数:此时 now('good') # 等价于 c_dec('execute')(now)('good') # 等价于 decorator(now)('good') # 等价于 wrapper_in('good') now('good') ######################################################### # 新增的功能 >>>接收到的字符串是:execute # 函数的原功能 >>>good
- 装饰器充要条件
- 必须有一个内嵌函数
- 内嵌函数必须引用外部嵌套函数中的变量
- 外部函数返回值必须是内嵌函数名
- 类实现装饰器:详见下一篇