异常处理

1. 异常的定义

异常是程序运行时发生错误的信号 , 一旦程序出错就会产生一个异常

如果该异常没有被处理 , 该异常就会被抛出来 , 程序的运行随之终止

2. 异常的组成

1. 具体哪一行代码抛出的异常

2. 异常的种类 : NameError IndexError KeyError AttributeError ValueError etc…

3. 异常的内容信息

3. 处理异常的目的

为了增强程序的健壮性 , 即在遇到错误时程序不会崩溃 , 我们需要对异常进行处理

4. 处理异常的方法

1. 针对语法的错误: 应该在程序运行前立即改正

2. 针对逻辑错误:

1. 如果逻辑错误发生的条件是可以预知的 , 应该 if 判断解决 , 预防异常

# 逻辑错误1
age = input(">>: ").strip()
if age.isdigit():
    age = int(age)
    if age > 18:
        print("too big")
    elif age < 18:
        print("too small")
    else:
        print("got it")
else:
    print("必须输入数字")

2. 如果逻辑错误发生的条件是不可预知的 , 那么异常一定会发生 , 考虑到程序的健壮性

我们应该处理异常 , 做好补救措施 , 需要用到 try … except : 在错误发生之后进行处理

# 逻辑错误2
try:
    # 代码块
except 异常的类型:
    # 发生异常后要执行的代码

5. 异常处理的种类

异常种类只能用来处理指定的异常情况 , 如果非指定异常则无法处理

IndexError 索引超出序列的范围 (索引不存在)

KeyError 字典中查找一个不存在的键

NameError 尝试访问一个不存在的变量 (变量名没有定义)

AttributeError 对象属性不存在 (尝试访问未知的对象属性) <=> 对象.属性

ValueError 传入一个调用者不期望的值,即使值的类型是正确的 <=> int(“abcd”)

TypeError 传入对象类型与要求的不符合 <=> “abcd”+1234

ZeroDivisionError 把0作为除数的错误 <=> 1/0

IndentationError 缩进错误 (代码没有正确对齐)

ImportError 无法引入模块或包 , 基本上是路径问题或名称错误

AssertionError 断言语句 (assert) 失败

StopIteration 迭代器没有更多的值

Exception 万能异常 (常见异常类的父类)

raise + 异常类型 主动触发异常

BaseException 所有异常类的父类 (基类 , 超类)

# 例1 异常种类只能用来处理指定的异常情况 , 如果非指定异常则无法处理
try:
    print("======>111")
    print("======>222")
    xxx
    print("======>333")
except AttributeError as e:
    print(e)
print('====>4')    
    
# 例2
try:
    print("======>111")
    print("======>222")
    xxx
    print("======>333")
except NameError as e:
    print(e)    
print('====>4')    
    
# 例3 多分支异常
try:
    print("======>111")
    print("======>222")
    xxx=111
    l=[]
    l[0]
    dic={}
    dic["k1"]
    print("======>333")
except (NameError,IndexError) as e:
    print(e)    
except KeyError as e:
    print(e)
finally:
    print("一定会运行")    
print('====>4')   
print(xxx)

# 例4
try:
    print("=======>111")
    print("=======>222")
finally:
    print("一定会运行")
print('====>4')

# 例5 万能异常 Exception
try:
    print("====>111")
    print("====>222")
    # xxx
    l=[]
    # l[0]
    dic={}
    dic["k1"]
    print("====>333")
except Exception as e:
    print("万能异常",e)
print('====>4')

# 例6 主动触发异常 raise + 异常错误类 or 异常错误类对象
print("====>1111")
raise NameError("变量名未定义")
print("====>2222")

class Animal:
    def speak(self):
        raise BaseException("小垃圾必须实现speak方法来覆盖")
        
    def run(self):
        raise BaseException("小垃圾必须实现run方法来覆盖")
        
class Dog(Animal):
    pass
class Pig(Animal):
    pass

d = Dog()
p = Pig()

d.speak()
d.run()

p.speak()
p.run()

# 基本语法
try:
	raise BaseException
except BaseException:
	pass
# 简写
try:
    raise
except:
    print("有异常错误")

# 例7 自定义异常 (必须继承父类 BaseException)
class Interface(BaseException):
    def __init__(self,msg,x,y,z):
        self.msg = msg
        self.x = x
        self.y = y
        self.z = z
        
    def __str__(self):
        return "<%s:%s:%s:%s>" % (self.msg,self.x,self.y,self.z)

raise Interface("接口异常",11,22,33)   

# 例8 断言: assert 条件
"""
断言就是猜的意思
assert 和 if 之间的区别:
	assert 在断言失败时,直接报错,抛出异常,后面的代码直接终止
	if     在判断为 False 的时候,不执行代码
"""
print("==========>111")
print("==========>222")
print("==========>333")
salaries = [1.1,2.2]

if len(salaries) != 3:
    raise NameError
   
salaries = [1.1,2.2,3.3]
assert len(salaries) == 3 
print(salaries[2])

# 处理迭代器异常错误
def mygen():
	print("start ... ")
	yield 1
	yield 2
	yield 3
	return 4

# 初始化生成器函数 -> 返回生成器对象 -> 简称生成器
gen = mygen()
try:
	res = next(gen)
	print(res)
	res = next(gen)
	print(res)
	res = next(gen)
	print(res)
	res = next(gen)
	print(res)
	
except StopIteration as e :
	# 为当前异常错误类StopIteration的对象起一个别名叫做e
	# 在StopIteration内部有__str__的方法
	# 在打印对象时,直接获取生成器中的return的返回值
	print(e)
	print("生成器停止迭代")

# 异常处理的其他写法
# 1.try ... finally ...  不论代码正确与否,都必须执行的代码放到finally当中.
"""一报错会终止掉程序,后面的代码不执行,有些必须要走的代码写在finally中"""
print("<===============>")
try:
	lst = [1,2,3]
	print(lst[90])
finally:
	print("被触发了..")

print(123)
print("<===============>")

# 2.try .. except .. else ...
"""如果try这个代码块没有异常错误,执行else这个分支,反之就不执行"""
print("<===============>")
try:
	lst = [1,2,3]
	print(lst[90])
except:
	pass
else:
	print("正常执行结束...")

# 3.try .. except .. else .. finally .. 
print("<=======111=======>")
try:
	lst = [1,2,3]
	print(lst[90])
except:
	print("异常处理222")
else:
	print("正常执行结束...")
finally:
	print("我被执行了111")
print("<======111=========>")

# (扩展)
# for/while  ... else .. 当循环遇到break异常终止循环时,不执行else分支
for i in range(10):
	if i  == 5:
		break
	# pass
else:
	print("循环结束")

# 质数: 除了1和它本身,不能再整除任何其他自然数的数是质数
n = 5
for i in range(2,n):
	if n % i == 0:
		print("不是质数")
		break
else:
	print("是质数")

6. 多分支异常与万能异常

1. 万能异常: 无论出现什么异常 , 统一使用同一段代码逻辑去处理 , 使用Exception

2. 多分支异常: 对于不同的异常定制不同的代码处理逻辑 , 使用多分支

3. 多分支异常后面可以添加一个 Exception 万能异常

7. 总结 try … except …

1. 把错误处理和真正的工作分开来

2. 代码更易组织 , 更清晰 , 复杂的工作任务更容易实现

3. 更安全 , 不至于由于一些小的疏忽而使程序意外崩溃

IndexError                索引超出序列的范围
KeyError                  字典中查找一个不存在的关键字
NameError                 尝试访问一个不存在的变量
IndentationError          缩进错误
AttributeError            尝试访问未知的对象属性
StopIteration             迭代器没有更多的值
AssertionError			 断言语句(assert)失败
EOFError                  用户输入文件末尾标志EOF(Ctrl+d)
FloatingPointError        浮点计算错误
GeneratorExit             generator.close()方法被调用的时候
ImportError               导入模块失败的时候
KeyboardInterrupt         用户输入中断键(Ctrl+c)
MemoryError               内存溢出(可通过删除对象释放内存)
NotImplementedError       尚未实现的方法
OSError                   操作系统产生的异常(例如打开一个不存在的文件)
OverflowError             数值运算超出最大限制
ReferenceError            弱引用(weak reference)试图访问一个已经被垃圾回收机制回收了的对象
RuntimeError              一般的运行时错误
SyntaxError               Python的语法错误
TabError                  Tab和空格混合使用
SystemError               Python编译器系统错误
SystemExit                Python编译器进程被关闭
TypeError                 不同类型间的无效操作
UnboundLocalError         访问一个未初始化的本地变量(NameError的子类)
UnicodeError              Unicode相关的错误(ValueError的子类)
UnicodeEncodeError        Unicode编码时的错误(UnicodeError的子类)
UnicodeDecodeError        Unicode解码时的错误(UnicodeError的子类)
UnicodeTranslateError     Unicode转换时的错误(UnicodeError的子类)
ValueError                传入无效的参数
ZeroDivisionError         除数为零

8. 获取错误行号和文件名

# 系统底层获取行数和文件名的函数 (只有在程序异常时才能触发) 
def return_errorinfo(n):
	import sys
	f = sys.exc_info()[2].tb_frame.f_back
	if n==1:		
		return str(f.f_lineno)      #返回当前行数
	elif n == 2:	
		return f.f_code.co_filename #返回文件名

socket 套接字编程

1. socket 的定义

网络基础 => socket

socket 是应用层与TCP/IP协议族通信的中间软件抽象层 , 它是一组接口. 在设计模式中 , socket 其实就是一个门面模式 , 把复杂的TCP/IP协议族隐藏在socket接口后面 , 对用户来说 , 一组简单的接口就是全部 , 让socket去组织数据 , 以符合指定的协议

2. 学习 socket 编程的目的

基于 socket 开发一个 C/S 或者 B/S 结构的软件

Client---------------网络---------------Server

Browser-----------网络---------------Server

3. 基于 socket 编程的方法

网络 : 底层的物理连接介质 + 互联网通信协议

网络存在的意义 : 通信

4. OSI 七层协议 / TCP/IP五层 / TCP/IP四层

1. 应用层 / 1. 应用层 / 1. 应用层

2. 表示层

3. 会话层

4. 传输层 / 2. 传输层 / 2. 传输层

5. 网络层 / 3. 网络层 / 3. 网络层

6. 数据链路层 / 4. 数据链路层 / 4. 网络接口层

7. 物理层 / 5. 物理层