高级异常、运算符重载
高级异常
回顾异常相关的语句:
try-except 用来捕获异常的通知
try-finally 用来做一定要做的事
reise 用来发生异常通知
assert 用来根据条件来发出AssertionError类型的异常通知
with语句
语句: with 表达式1 [as 变量1],表达式2 [as 变量2]:
语句块
作用:使用于对资源进行访问的场合,确保使用过程中不管是否发生异常,都会执行必须的'清理'操作,并释放资源
如:文件使用后自动关闭;线程中锁定的自动获取和释放等
1 def read_from_file(filename='info.txt'): 2 try: 3 with open(filename) as f: 4 print("正在读取文件") 5 n = int(f.read()) 6 print('n=', n) 7 print('文件已经关闭') 8 # f = open(filename) 9 # try: 10 # print("正在读取文件") 11 # n = int(f.read()) 12 # print("n=", n) 13 # finally: 14 # f.close() 15 # print("文件已经关闭") 16 except OSError: 17 print("文件打开失败") 18 19 20 read_from_file()
环境管理器
1、类内有__enter__和__exit__实例方法的类被称为环境管理器
2、能够用with语句管理的对象必须是环境管理器
3、 __enter__方法将在进入with语句时被调用,并返回由as变量管理的对象
4、__exit__将在离开with语句时被调用,且可以用参数来判断在离开with语句时是否有异常发生并做出相应的处理
1 class A: 2 def __enter__(self): 3 print("已进入with语句") 4 return self # 返回的对象将由 as绑定 5 6 def __exit__(self, exc_type, exc_val, exc_tb): 7 print("已离开with语句") 8 # a = A() 9 with A() as a: 10 print("这是with语句内的一条语句") 11 int(input("请输入整数: "))
1 已进入with语句 2 这是with语句内的一条语句 3 请输入整数: 2 4 已离开with语句
对象的属性管理函数:
1、getattr(obj, name[, default])从一个对象得到对象的属性;getattr(x, 'y') 等同于x.y;当属性不存在时,如果给出default参数,则返回default,如果没有给出default则产生一个AttributeError错误
2、hasattr(obj, name)用给定的name返回对象obj是否有此属性,此种做法可以避免在getattr(obj, name)时引发错误
3、setattr(obj, name, value)给对象obj的名为name的属性设置相应的值value, set(x,'y', v) 等同于 x.y = v
4、delattr(obj, name)删除对象obj中的name属性,delattr(x, 'y') 等同于 del x.y
1 class Car: 2 def __init__(self, c, b): 3 self.color, self.brand = c, b 4 5 def get_car_attr(self, attr_name): 6 '''此方法用于获取对象的属性,如果属性名attr_name 7 在此对象内不存在则返回 None 8 ''' 9 return getattr(self, attr_name, None) 10 11 c1 = Car('黑色', 'Benz') 12 v = c1.get_car_attr('color') 13 # try: 14 # v = c1.__dict__['aaaaa'] 15 # except KeyError: 16 # v = None 17 if v is None: 18 print("没有颜色属性") 19 else: 20 print("颜色是:", v)
运算符重载
让自定义的类生成的对象(实例)能够使用运算符进行操作
作用:让自定义的类的实例像内建对象一样能够运行运算符操作,让程序简单易读,对自定义的对象,将运算符赋予新的运算规则
算术运算符的重载:
__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 hands side) 右手边
1 class MyNumber: 2 def __init__(self, v): 3 self.data = v 4 5 def __repr__(self): 6 return 'MyNumber(%d)' % self.data 7 8 # def myadd(self, other): 9 # v = self.data + other.data 10 # return MyNumber(v) 11 12 def __add__(self, other): 13 print("__add__被调用") 14 v = self.data + other.data 15 return MyNumber(v) 16 17 def __sub__(self, rhs): 18 v = self.data - rhs.data 19 return MyNumber(v) 20 21 n1 = MyNumber(100) 22 n2 = MyNumber(200) 23 # n3 = n1.myadd(n2) 24 # n3 = n1.__add__(n2) 25 n3 = n1 + n2 # __add__被调用 26 print(n3) # MyNumber(300) 27 n4 = n3 - n2 28 print(n4) # MyNumber(100)
1 class MyList: 2 def __init__(self, iterable): 3 self.data = list(iterable) 4 5 def __add__(self, rhs): 6 return MyList(self.data + rhs.data) 7 8 def __repr__(self): 9 return 'MyList(%r)' % self.data 10 11 def __mul__(self, rhs): # rhs 绑定整数 12 return MyList(self.data * rhs) 13 14 L1 = MyList([1, 2, 3]) 15 L2 = MyList([4, 5, 6]) 16 L3 = L1 + L2 # 等同于L1.__add__(L2) 17 print(L3) # MyList([1,2,3,4,5,6]) 18 L4 = L2 + L1 # 等同于L2.__add__(L1) 19 print(L4) # MyList([4,5,6,1,2,3]) 20 L5 = L1 * 2 # L1.__mul__(2) 21 print(L5) # MyList([1,2,3,1,2,3])
反向算术运算符的重载
__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 冪
1 class MyList: 2 def __init__(self, iterable): 3 self.data = list(iterable) 4 5 def __add__(self, rhs): 6 return MyList(self.data + rhs.data) 7 8 def __repr__(self): 9 return 'MyList(%r)' % self.data 10 11 def __mul__(self, rhs): # rhs 绑定整数 12 print('__mul__被调用') 13 return MyList(self.data * rhs) 14 def __rmul__(self, lhs): 15 print('__rmul__被调用') 16 return MyList(self.data * lhs) 17 18 L1 = MyList([1, 2, 3]) 19 L2 = MyList([4, 5, 6]) 20 L5 = L1 * 2 # L1.__mul__(2) 21 print(L5) # MyList([1,2,3,1,2,3]) 22 23 L6 = 2 * L1 # 2.__mul__(L1) 24 print(L6)
复合赋值算术运算符的重载
__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 冪
1 class MyList: 2 def __init__(self, iterable): 3 print("aaaaaaaaaaaaaaaaaaaaaaaaaaaaa") 4 self.data = list(iterable) 5 6 def __add__(self, rhs): 7 print('__add__被调用') 8 return MyList(self.data + rhs.data) 9 10 def __repr__(self): 11 return 'MyList(%r)' % self.data 12 13 def __iadd__(self, rhs): 14 print("__iadd__被调用!!!!") 15 self.data.extend(rhs.data) 16 return self 17 18 L1 = MyList([1, 2, 3]) # aaaaaaaaaaaaaaaaaaaaaaaaaaaaa 19 L2 = MyList([4, 5, 6]) # aaaaaaaaaaaaaaaaaaaaaaaaaaaaa 20 L1 += L2 # 当没有__iadd__方法时,等同于调用L1 = L1 + L2 __iadd__被调用!!!! 21 print(L1) # MyList([1, 2, 3, 4, 5, 6])
比较运算符的重载
__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
位运算符重载
__invert__(self) ~ self 取反(一元运算符)
__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):
1 class MyList: 2 def __init__(self, iterable): 3 print("__init__被调用") 4 self.data = list(iterable) 5 6 def __repr__(self): 7 return 'MyList(%r)' % self.data 8 9 def __neg__(self): 10 '''此方法用来制定 - self 返回的规则''' 11 # L = [-x for x in self.data] 12 L = (-x for x in self.data) 13 return MyList(L) 14 15 L1 = MyList([1, -2, 3, -4]) 16 L2 = -L1 17 print(L2)
运算符重载说明:
运算符重载不能改变运算符的优先级
Python类名最好用驼峰命名法:
MyList MyRange 大驼峰(所有单词首字母大写,其余小写)
getStudentAge 小驼峰(第一个单词首字母小写,其它首字母大写)
in / not in 运算符的重载
重载方法:
__contains__(self, e) e in self 成员运算
1 class MyList: 2 def __init__(self, iterable): 3 print("__init__被调用") 4 self.data = list(iterable) 5 6 def __repr__(self): 7 return 'MyList(%r)' % self.data 8 9 def __contains__(self, e): 10 '''此方法用来实现 in / not in 运算符的重载''' 11 print("__contains__被调用") 12 for x in self.data: 13 if x == e: 14 return True 15 return False 16 17 18 L1 = MyList([1, -2, 3, -4]) 19 if -2 in L1: 20 print('-2 在 L1 中') 21 else: 22 print('-2 不在 L1中') 23 24 25 # 当MyList的类内重载了__contains__方法,则not in也同时可用 26 if -3 not in L1: 27 print("-3 不在 L1中") 28 else: 29 print('-3 在 L2中')
索引和切片运算符的重载
__getitem__(self, i) x = self[i] 索引/切片取值
__setitem__(self, i, v) self[i] = v 索引/切片赋值
__delitem__(self, i) del self[i] del语句删除索引等
作用:
让自定义的类型的对象能够支持索引和切片操作
1 class MyList: 2 def __init__(self, iterable): 3 print("__init__被调用") 4 self.data = list(iterable) 5 6 def __repr__(self): 7 return 'MyList(%r)' % self.data 8 9 def __getitem__(self, i): 10 print("__getitem__被调用, i=", i) 11 # if type(i) is not int: 12 # raise TypeError 13 return self.data[i] 14 15 def __setitem__(self, i, v): 16 print("__setitem__被调用, i=", i, 'v =', v) 17 self.data[i] = v # 修改data绑定的列表 18 19 20 L1 = MyList([1, -2, 3, -4]) 21 v = L1[-1] 22 print(v) 23 24 L1[1] = 2 # 等同于调用 L1.__setitem__(1, 2) 25 print(L1) 26 27 # 以下操作会出错 28 # print(L1[100000000000]) 29 # print(L1['hello'])
slice 构造函数
作用: 用于创建一个Slice切片对象, 此对象存储一个切片的起始值,终止值和步长信息
slice(start, stop=None, step=None) 创建一个切片对象
slice的对象的属性:
s.start 切片起始值,默认为None
s.stop 切片终止值,默认为None
s.step 切片步长 ,默认为None
1 class MyList: 2 def __init__(self, iterable): 3 print("__init__被调用") 4 self.data = list(iterable) 5 6 def __repr__(self): 7 return 'MyList(%r)' % self.data 8 9 def __getitem__(self, i): 10 print("__getitem__被调用, i=", i) 11 if type(i) is int: 12 print("正在做索引操作") 13 elif type(i) is slice: 14 print("正在做切片操作") 15 print("切片的起始值:", i.start) 16 print("切片的终止值:", i.stop) 17 print("切片的步长:", i.step) 18 else: 19 raise KeyError 20 return self.data[i] 21 22 23 L1 = MyList([1, -2, 3, -4, 5, -6]) 24 25 print(L1[::2]) # 等同于调用L1[slice(None, None, 2)]