异常(高级) Exception
异常回顾: try-except 语句 捕获(接收)异常通知,把异常流程变为正常流程 try-finally 语句 执行必须要执行的语句. raise 语句 发送异常通知,同时进入异常流程 assert 语句 发送AssertionError异常 with 语句
with语句 语法: with 表达式1 [as 变量1], 表达式2 [as 变量2], ...: 语句块 作用: 使用于对资源进行访问的场合,确保使用过程中不管是否发生异常都会执行必要的清理操作,并释放资源 如: 文件使用后自动关闭,线程中锁的自动获取和释放等
try:
# file = open("../day19.txt")
with open('../day19.txt') as file:
line1 = file.readline()
print("第一行内容是:", line1)
n = int(line1) # with语句保证在出异时,文件也能被关闭
print(n)
except OSError:
print("文件打开失败")
except ValueError:
print('读写文件时出错')
View Code
说明: with语句同try-finally语句一样,不会改变程序的状态(异常或正常状态)
环境管理器: 类内有'__enter__' 和 '__exit__' 实例方法的类被称为环境管理器能够用with语句进行管理的对象必须是环境管理器 __enter__将在进入with语句之前被调用,并返回由as 变量管理的对象 __exit__ 将在离开with语句时被调用,且可以用参数来判断在离开with语句时是否有异常发生并做出相应的处理
class A:
def __enter__(self):
print("__enter__方法被调用")
# 此处打开文件
return self # self 将被with as后的变量绑定
def __exit__(self, exc_type, exc_val, exc_tb):
print("__exit__方法被调用")
# 此处关闭文件
if exc_type is None:
print("正常离开with语句")
else:
print("异常离开with语句")
print(exc_type, exc_val, exc_tb)
try:
with A() as a:
print("这是with内的语句")
err = ValueError("故意抛出一个错误")
raise err
except ValueError:
print("with语句内出现异常!!")
View Code
异常类: BaseExcetion 类是一切异常类的基类 自定义的异常类型必须直接或间接的继承自BaseExcetion类
运算符重载 让自定义的类生成的对象(实例) 能够使用运算符进行操作
作用: 让自定义类的实例像内建对象一样进行运算符操作 让程序简洁易读 对自定义对象将运算符赋予新的运算规则
说明: 运算符已经有固定的含义,不建议改变原有运算符的含义 方法名 运算符和表达式 说明 __add__(self, rhs) self + rhs 加法 __sub__(self, rhs) self - rhs 减法 __mul__(self, rhs) self * rhs 乘法 __truediv__(self, rhs) self / rhs 除法 __floordiv__(self, rhs) self // rhs 地板除法 __mod__(self, rhs) self % rhs 求余 __pow__(self, rhs) self ** rhs 幂运算
rhs (right hand side) 右手边
二元运算符的重载方法: def __xxx__(self, other): ...
class MyNumber:
def __init__(self, value):
self.data = value
def __repr__(self):
return "MyNumber(%d)" % self.data
def __add__(self, other):
temp = self.data + other.data
obj = MyNumber(temp) # 创建一个新的对象
return obj
def __sub__(self, other):
temp = self.data - other.data
obj = MyNumber(temp) # 创建一个新的对象
return obj
n1 = MyNumber(100)
n2 = MyNumber(200)
# n3 = n1.__add__(n2)
n3 = n1 + n2 # 等同于 n3 = n1.__add__(n2)
print(n1, "+", n2, '=', n3)
n4 = n1 - n2
print(n1, "-", n2, '=', n4)
View Code
反向算术运算符的重载 当运算符的左侧为内建类型时,右侧为自定义类的对象进行算术运算符运算时,会出现TypeError错误,因无法修改内建类型的代码来实现运算符重载,此时需要反向算术运算符重载
方法如下: 方法名 运算符和表达式 说明 __radd__(self, lhs) lhs + self 加法 __rsub__(self, lhs) lhs + self 减法 __rmul__(self, lhs) lhs * self 乘法 __rtruediv__(self, lhs) lhs / self 除法 __rfloordiv__(self, lhs) lhs // self 地板除法 __rmod__(self, lhs) lhs % self 求余 __rpow__(self, lhs) lhs ** self 幂运算
lhs (left hand side) 左手边
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __add__(self, rhs):
L = self.data + rhs.data
return MyList(L)
def __repr__(self):
return "MyList(%s)" % self.data
def __mul__(self, rhs):
L = self.data * rhs
return MyList(L)
def __rmul__(self, lhs):
print("__rmul__被调用")
return MyList(self.data * lhs)
L1 = MyList(range(1, 4))
L2 = MyList([4, 5, 6])
L5 = L1 * 2 # L5 = L1.__mul__(2)
print(L5) # MyList([1, 2, 3, 1, 2, 3])
L6 = 2 * L1 # L1.__rmul__(2) 2.__mul__(L1)
print(L6) # ???
View Code
复合赋值算术运算符的重载 以复合赋值算述运算符 x += y 主为例,此运算符会优先调用x.__iadd__(y) ,如果没有__iadd__方法时,会将复合赋值运算符拆解为 x = x + y然后调用x = x.__add__(y)方法,如再不存在__add__方法,则会触发TypeError错误 其它复合赋值运算符有相同的规则
方法名 运算符和表达式 说明 __iadd__(self, rhs) self += rhs 加法 __isub__(self, rhs) self -= rhs 减法 __imul__(self, rhs) self *= rhs 乘法 __itruediv__(self, rhs) self /= rhs 除法 __ifloordiv__(self, rhs) self //= rhs 地板除法 __imod__(self, rhs) self %= rhs 求余 __ipow__(self, rhs) self **= rhs 幂运算
rhs (right hand side) 右手边
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
return "MyList(%s)" % self.data
def __add__(self, rhs):
print("__add__")
L = self.data + rhs.data
return MyList(L)
# def __iadd__(self, rhs):
# print("__iadd__")
# self.data += rhs.data
# return self
L1 = MyList(range(1, 4))
L2 = MyList([4, 5, 6])
print("+= 之前的 id(L1)", id(L1))
L3 = L1
L1 += L2
print("+= 之后的 id(L1)", id(L1))
print(L1)
print(L3)
View Code
比较运算符的重载 方法名 运算符和表达式 说明 __lt__(self, rhs) self < rhs 小于 __le__(self, rhs) self <= rhs 小于等于 __gt__(self, rhs) self > rhs 大于 __ge__(self, rhs) self >= rhs 大于等于 __eq__(self, rhs) self == rhs 等于 __ne__(self, rhs) self != rhs 不等于
注: 比较运算符通常返回布尔值 True 或 False
位运算符的重载 方法名 运算符和表达式 说明 __and__(self, rhs) self & rhs 位与 __or__(self, rhs) self | rhs 位或 __xor__(self, rhs) self ^ rhs 位异与 __lshift__(self, rhs) self << rhs 左移 __rshift__(self, rhs) self >> rhs 右移
反向位运算符的重载 方法名 运算符和表达式 说明 __rand__(self, lhs) lhs & self 位与 __ror__(self, lhs) lhs | self 位或 __rxor__(self, lhs) lhs ^ self 位异与 __rlshift__(self, lhs) lhs << self 左移 __rrshift__(self, lhs) lhs >> self 右移
复合赋值位运算符的重载 方法名 运算符和表达式 说明 __iand__(self, rhs) self &= rhs 位与 __ior__(self, rhs) self |= rhs 位或 __ixor__(self, rhs) self ^= rhs 位异与 __ilshift__(self, rhs) self <<= rhs 左移 __irshift__(self, rhs) self >>= rhs 右移
一元运算符的重载 方法名 运算符和表达式 说明 __neg__(self) -self 负号 __pos__(self) +self 正号 __invert__(self) ~self 取反
一元运算符的重载语法: class 类名: def __xxx__(self): ...
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
return "MyList(%s)" % self.data
def __neg__(self):
return MyList([-x for x in self.data])
L1 = MyList([1, -2, 3, -4, 5])
L2 = -L1
print(L2) # MyList([-1, 2, -3, 4, -5])
View Code
in , not in 运算符的重载 方法名 运算符和表达式 说明 __contains__(self, e) e in self 成员运算
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
return "MyList(%s)" % self.data
def __contains__(self, item):
return item in self.data
L1 = MyList([1, -2, 3, -4, 5])
if 3 in L1:
print("真")
else:
print("假")
print(3 not in L1)
View Code
索引和切片运算符的重载: 重载方法 方法名 运算符和表达式 说明 __getitem__(self, i) x = self 索引/切片取值 __setitem__(self, i, v) self = v 索引/切片赋值 __delitem__(self, i) del self 删除索引/切片
作用: 让自定义的类型的对象能够支持索引和切片操作
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
return "MyList(%s)" % self.data
def __getitem__(self, item):
print("__getitem__", item)
return self.data[item]
def __setitem__(self, key, value):
print("__setitem__(key=", key, ',value=', value,')')
self.data[key] = value
def __delitem__(self, key):
print('正在删除第', key, '个元素')
L1 = MyList([1, -2, 3, -4, 5])
v = L1[2] # 调用 v = L1.__getitem__(2)
print(v) # 3
L1[1] = 2 # 调用 L1.__setitem__(1, 2)
print(L1)
del L1[3] # 调用 L1.__delitem__(3)
View Code
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
return "MyList(%s)" % self.data
def __getitem__(self, item):
print("__getitem__:", item)
if type(item) is int:
print("正在做索引操作,item=", item)
elif type(item) is slice:
print("正在做切片操作:")
print("起始值:", item.start)
print("终止值:", item.stop)
print("步长:", item.step)
return self.data[item]
L1 = MyList([1, -2, 3, -4, 5])
v = L1[1::2]
print(v)
v = L1[3]
print(v)
# L1[1:2:3] = [4, 5, 6]
# L1.__setitem__(slice(1, 2, 3), [4, 5, 6])
View Code
slice 构造函数 作用: 用于创建一个slice切片对象,此对象存储一个切片的起始值,终止值,步长信息 格式: slice(start=None, stop=None, step=None) slice对象的实例属性 s.start 切片的起始值,默认为None s.stop 切片的终止值,默认为None s.step 切片的步长,默认为None
特性属性 @property 实现其它语言所拥有的getter 和 setter功能 作用: 用来模拟一个属性 通过@property装饰器可以对模拟属性赋值和取值加以控制
class Student:
def __init__(self, s):
self.__score = s # 成绩
@property
def score(self):
'''getter'''
return self.__score
@score.setter
def score(self, new_score):
'''setter'''
assert 0 <= new_score <= 100, '成绩不合法'
self.__score = new_score
s1 = Student(50)
print(s1.score)
s1.score = 999 # 用setter来控制赋值操作
print(s1.score)
View Code
|